306 lines
9.8 KiB
TypeScript

import { PsdLayerSource } from "../_declare";
import { LayerType } from "./LayerType";
import { Size } from "../values/Size";
import { Vec2 } from "../values/Vec2";
import { utils } from "../utils/Utils";
import { UIObject } from "../engine/UIObject";
import { Rect } from "../values/Rect";
import { Color } from "../values/Color";
import { Vec3 } from "../values/Vec3";
import { pinyin } from "pinyin-pro";
/**
* 命名规则
* "name@Type{prop: 1,prop2: 2}"
* Type = btn | bar | (toggle @check) | .9 |
*
*/
export interface PsdAttr {
name: string,
comps: {
Btn?: {};
btn?: {};
ProgressBar?: {};
progressBar?: {};
bar?: {};
Toggle?: {};
toggle?: {};
check?: {};
".9"?: { l?: number, r?: number, b?: number, t?: number };
ar?: { x?: number, y?: number };
// 忽略导出节点和图片
ignore?: {};
ig?: {};
// 忽略导出节点
ignorenode?: {};
ignode?: {};
// 忽略导出图片
ignoreimg?: {};
igimg?: {};
full?: {};
// size?: { w?: number, h?: number };
// scale?: { x?: number, y?: number };
img?: { id?: number, name?: string, bind?: number }
flip?: { bind: number, x?: number, y?: number }
flipX?: { bind: number }
flipY?: { bind: number }
// position?:{x?: number,y?: number};
// pos?:{x?: number,y?: number};
}
}
export abstract class PsdLayer {
static isPinyin = false;
declare uuid: string;
declare rootDoc: PsdLayer;
declare name: string;
declare source: PsdLayerSource;
declare parent: PsdLayer;
declare position: Vec2;
declare size: Size;
declare rect: Rect;
declare anchorPoint: Vec2;
declare hidden: boolean;
declare opacity: number;
declare layerType: LayerType;
declare uiObject: UIObject;
declare attr: PsdAttr; // 解析名字获得各项属性
declare color: Color;
declare scale: Vec3;
constructor(source: any, parent: PsdLayer, rootDoc: PsdLayer) {
this.uuid = utils.uuid();
this.source = source;
this.parent = parent;
this.rootDoc = rootDoc;
this.name = source.name;
this.position = new Vec2();
this.size = new Size();
this.rect = new Rect(source);
// this.anchorPoint = new Vec2();
this.anchorPoint = new Vec2(0.5, 0.5);
this.hidden = false;
this.opacity = 255;
this.color = new Color(255, 255, 255, 255);
console.log(`PsdLayer->解析到图层 `, this.name);
this.attr = this.parseNameRule(this.name);
// // 更新名字
this.name = this.chineseToPinyin(this.attr?.name || this.name);
// 使用配置的缩放系数
// let _scale = this.attr?.comps.scale;
// this.scale = new Vec3(_scale?.x ?? 1, _scale?.y ?? 1, 1);
this.scale = new Vec3(1, 1, 1);
}
abstract onCtor();
parseNameRule(name: string) {
if (!name) {
return;
}
name = name.trim();
let fragments = name.split("@");
if (fragments.length === 0) {
console.error(`PsdLayer-> 名字解析错误`);
return;
}
let obj: PsdAttr = {
name: fragments[0]?.replace(/\.|>|\/|\ /g, "_") ?? "unknow",
comps: {},
}
for (let i = 1; i < fragments.length; i++) {
const fragment = fragments[i].trim();
let attr = {};
let startIdx = fragment.indexOf("{");
let comp = fragment;
if (startIdx != -1) {
let endIdx = fragment.indexOf("}");
if (endIdx == -1) {
console.log(`PsdLayer->${name} 属性 解析错误`);
continue;
}
let attrStr = fragment.substring(startIdx + 1, endIdx);
comp = fragment.substr(0, startIdx);
attrStr = attrStr.trim();
let attrs = attrStr.split(",");
attrs.forEach((str) => {
str = str.trim();
let strs = str.split(":");
if (!strs.length) {
console.log(`PsdLayer->${name} 属性 解析错误`);
return;
}
strs.map((v) => {
return v.trim();
});
attr[strs[0]] = utils.isNumber(strs[1]) ? parseFloat(strs[1]) : strs[1];
});
}
comp = comp.trim();
comp = comp.replace(":", ""); // 防呆,删除 key 中的冒号,
obj.comps[comp] = attr;
}
// 获取别名的值
obj.comps.ignore = obj.comps.ignore || obj.comps.ig;
obj.comps.ignorenode = obj.comps.ignorenode || obj.comps.ignode;
obj.comps.ignoreimg = obj.comps.ignoreimg || obj.comps.igimg;
obj.comps.Btn = obj.comps.Btn || obj.comps.btn;
obj.comps.ProgressBar = obj.comps.ProgressBar || obj.comps.progressBar;
obj.comps.Toggle = obj.comps.Toggle || obj.comps.toggle;
// 图片名中文转拼音
if (obj.comps.img) {
if (obj.comps.img.name) {
obj.comps.img.name = this.chineseToPinyin(obj.comps.img.name);
}
}
// 将mirror filpX filpY 进行合并
if (obj.comps.flip || obj.comps.flipX || obj.comps.flipY) {
obj.comps.flip = Object.assign({}, obj.comps.flip, obj.comps.flipX, obj.comps.flipY);
if (obj.comps.flipX) {
obj.comps.flip.x = 1;
}
if (obj.comps.flipY) {
obj.comps.flip.y = 1;
}
// x,y 都缺省时,默认 x 方向镜像
if (typeof obj.comps.flip.bind !== 'undefined') {
if (!obj.comps.flip.y) {
obj.comps.flip.x = 1;
}
// 只有作为镜像图片使用的时候才反向赋值
// 反向赋值,防止使用的时候值错误
if (obj.comps.flip.x) {
obj.comps.flipX = Object.assign({}, obj.comps.flipX, obj.comps.flip);
}
if (obj.comps.flip.y) {
obj.comps.flipY = Object.assign({}, obj.comps.flipY, obj.comps.flip);
}
}
}
// // 检查冲突
// if (obj.comps.full && obj.comps.size) {
// console.warn(`PsdLayer->${obj.name} 同时存在 @full 和 @size`);
// }
return obj;
}
/** 解析数据 */
parseSource() {
let _source = this.source;
// psd文档
if (!this.parent) {
return false;
}
this.hidden = _source.hidden;
this.opacity = Math.round(_source.opacity * 255);
// 获取锚点
let ar = this.attr.comps.ar;
if (ar) {
this.anchorPoint.x = ar.x ?? this.anchorPoint.x;
this.anchorPoint.y = ar.y ?? this.anchorPoint.y;
}
this.computeBasePosition();
return true;
}
/** 解析 effect */
parseEffects() {
// 颜色叠加 暂时搞不定
// if(this.source.effects?.solidFill){
// let solidFills = this.source.effects?.solidFill;
// for (let i = 0; i < solidFills.length; i++) {
// const solidFill = solidFills[i];
// if(solidFill.enabled){
// let color = solidFill.color;
// this.color = new Color(color.r,color.g,color.b,solidFill.opacity * 255);
// }
// }
// }
}
/** 中文转拼音 */
chineseToPinyin(text: string) {
if (!text || !PsdLayer.isPinyin) {
return text;
}
let reg = new RegExp("[\\u4E00-\\u9FFF]+", "g");
if (!reg.test(text)) {
return text;
}
let names = pinyin(text, {
toneType: "none",
type: "array"
});
names = names.map((text) => {
return text.slice(0, 1).toUpperCase() + text.slice(1).toLowerCase();
});
return names.join("");
}
// 计算初始坐标 左下角 0,0 为锚点
computeBasePosition() {
if (!this.rootDoc) {
return;
}
let _rect = this.rect;
let width = (_rect.right - _rect.left);
let height = (_rect.bottom - _rect.top);
this.size.width = width;
this.size.height = height;
// 位置 左下角为锚点
let x = _rect.left;
let y = (this.rootDoc.size.height - _rect.bottom);
this.position.x = x;
this.position.y = y;
}
// 根据锚点计算坐标
updatePositionWithAR() {
if (!this.parent) {
return;
}
let parent = this.parent;
while (parent) {
this.position.x -= parent.position.x;
this.position.y -= parent.position.y;
parent = parent.parent;
}
// this.position.x = this.position.x - this.parent.size.width * this.parent.anchorPoint.x + this.size.width * this.anchorPoint.x;
// this.position.y = this.position.y - this.parent.size.height * this.parent.anchorPoint.y + this.size.height * this.anchorPoint.y;
this.position.x = this.position.x - this.rootDoc.size.width * this.rootDoc.anchorPoint.x + this.size.width * this.anchorPoint.x;
this.position.y = this.position.y - this.rootDoc.size.height * this.rootDoc.anchorPoint.y + this.size.height * this.anchorPoint.y;
}
}