二七王:LayoutSolver attach 加 ctx.w/ctx.h 运行时尺寸注入通道
求解冒烟守卫拿真实布局配置跑出 9 个失败节点:叫分档位分数文字、花色数量 文字、牌角标、结算文案等动态文字标签配置里有意不写 w/h(真实宽高要等 文案渲染出来才知道),此前的按对齐模式校验因此在 hAlign=center/right、 corner=topRight/bottomRight 时正确地抛错,但没给调用方注入真实尺寸的通道。 补 ctx.w/ctx.h,语义与已有的 ctx.target 对称:优先于配置里的 n.w/n.h, 校验与求解都用合并后的值,返回的 width/height 也用合并后的值(不再是 可能为 undefined 的配置原值);两处都缺且用得到该维度时仍抛错,错误信息 点明"配置未写 X,且 ctx.X 未给出"两条路径。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -171,8 +171,9 @@ var EQW_LayoutSolver = EQW_LayoutSolver || {
|
|||||||
},
|
},
|
||||||
|
|
||||||
//attach:贴在另一个精灵上。corner 为空 = 在目标【内部】对齐;有值 = 与目标对应角重合
|
//attach:贴在另一个精灵上。corner 为空 = 在目标【内部】对齐;有值 = 与目标对应角重合
|
||||||
//target 支持运行时注入:叫分档位贴自己的按钮、花色图标贴自己的按钮、牌角标贴"打出的那张牌",
|
//target/w/h 都支持运行时注入:叫分档位贴自己的按钮、花色图标贴自己的按钮、牌角标贴"打出的那张牌",
|
||||||
//这类目标配置里写不出固定值,节点写成无 target 的模板,由 ctx.target 在运行时补上(ctx.target 优先于 n.target)
|
//这类目标配置里写不出固定值;动态文字标签的真实宽高要等文案渲染出来才知道,配置里也留空。
|
||||||
|
//这些节点写成模板,由 ctx.target/ctx.w/ctx.h 在运行时补上(ctx.* 优先于 n.* 里的同名字段)
|
||||||
_solveAttach: function (n, ctx) {
|
_solveAttach: function (n, ctx) {
|
||||||
if (!ctx.rects) { throw new Error('[EQW_LayoutSolver] attach 需要 ctx.rects'); }
|
if (!ctx.rects) { throw new Error('[EQW_LayoutSolver] attach 需要 ctx.rects'); }
|
||||||
var targetKey = ctx.target || n.target;
|
var targetKey = ctx.target || n.target;
|
||||||
@@ -180,7 +181,11 @@ var EQW_LayoutSolver = EQW_LayoutSolver || {
|
|||||||
var target = ctx.rects[targetKey];
|
var target = ctx.rects[targetKey];
|
||||||
if (!target) { throw new Error('[EQW_LayoutSolver] attach 的 target 未在 ctx.rects 中: ' + targetKey); }
|
if (!target) { throw new Error('[EQW_LayoutSolver] attach 的 target 未在 ctx.rects 中: ' + targetKey); }
|
||||||
|
|
||||||
var sprite = { width: n.w, height: n.h };
|
//ctx.w/ctx.h 优先于配置里的 n.w/n.h;后续的校验、求解、返回值一律用合并后的值
|
||||||
|
var w = (typeof ctx.w === 'number') ? ctx.w : n.w;
|
||||||
|
var h = (typeof ctx.h === 'number') ? ctx.h : n.h;
|
||||||
|
|
||||||
|
var sprite = { width: w, height: h };
|
||||||
var offset = { x: n.offsetX || 0, y: n.offsetY || 0 };
|
var offset = { x: n.offsetX || 0, y: n.offsetY || 0 };
|
||||||
var pos;
|
var pos;
|
||||||
|
|
||||||
@@ -191,41 +196,41 @@ var EQW_LayoutSolver = EQW_LayoutSolver || {
|
|||||||
case 'topLeft':
|
case 'topLeft':
|
||||||
pos = AlignmentUtils.alignCornerTopLeft(target, sprite, offset); break;
|
pos = AlignmentUtils.alignCornerTopLeft(target, sprite, offset); break;
|
||||||
case 'topRight':
|
case 'topRight':
|
||||||
this._requireW(n, targetKey, 'corner=topRight');
|
this._requireW(w, targetKey, 'corner=topRight');
|
||||||
pos = AlignmentUtils.alignCornerTopRight(target, sprite, offset); break;
|
pos = AlignmentUtils.alignCornerTopRight(target, sprite, offset); break;
|
||||||
case 'bottomLeft':
|
case 'bottomLeft':
|
||||||
this._requireH(n, targetKey, 'corner=bottomLeft');
|
this._requireH(h, targetKey, 'corner=bottomLeft');
|
||||||
pos = AlignmentUtils.alignCornerBottomLeft(target, sprite, offset); break;
|
pos = AlignmentUtils.alignCornerBottomLeft(target, sprite, offset); break;
|
||||||
case 'bottomRight':
|
case 'bottomRight':
|
||||||
this._requireW(n, targetKey, 'corner=bottomRight');
|
this._requireW(w, targetKey, 'corner=bottomRight');
|
||||||
this._requireH(n, targetKey, 'corner=bottomRight');
|
this._requireH(h, targetKey, 'corner=bottomRight');
|
||||||
pos = AlignmentUtils.alignCornerBottomRight(target, sprite, offset); break;
|
pos = AlignmentUtils.alignCornerBottomRight(target, sprite, offset); break;
|
||||||
default: throw new Error('[EQW_LayoutSolver] 未知 corner: ' + n.corner);
|
default: throw new Error('[EQW_LayoutSolver] 未知 corner: ' + n.corner);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//hAlign: center/right 要用 sprite.width;left 不用(AlignmentUtils.js 第106/111/101行)
|
//hAlign: center/right 要用 sprite.width;left 不用(AlignmentUtils.js 第106/111/101行)
|
||||||
if (n.hAlign === 'center' || n.hAlign === 'right') {
|
if (n.hAlign === 'center' || n.hAlign === 'right') {
|
||||||
this._requireW(n, targetKey, 'hAlign=' + n.hAlign);
|
this._requireW(w, targetKey, 'hAlign=' + n.hAlign);
|
||||||
}
|
}
|
||||||
//vAlign: 只有 middle 用 sprite.height;top/bottom 都不用(bottom 用的是 target.height,第132行)
|
//vAlign: 只有 middle 用 sprite.height;top/bottom 都不用(bottom 用的是 target.height,第132行)
|
||||||
if (n.vAlign === 'middle') {
|
if (n.vAlign === 'middle') {
|
||||||
this._requireH(n, targetKey, 'vAlign=' + n.vAlign);
|
this._requireH(h, targetKey, 'vAlign=' + n.vAlign);
|
||||||
}
|
}
|
||||||
pos = AlignmentUtils.alignTo(target, sprite, n.hAlign, n.vAlign, offset);
|
pos = AlignmentUtils.alignTo(target, sprite, n.hAlign, n.vAlign, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [{ x: pos.x, y: pos.y, width: n.w, height: n.h }];
|
return [{ x: pos.x, y: pos.y, width: w, height: h }];
|
||||||
},
|
},
|
||||||
|
|
||||||
_requireW: function (n, targetKey, mode) {
|
_requireW: function (w, targetKey, mode) {
|
||||||
if (typeof n.w !== 'number') {
|
if (typeof w !== 'number') {
|
||||||
throw new Error('[EQW_LayoutSolver] attach target=' + targetKey + '(' + mode + ')需要数字 w,当前缺失');
|
throw new Error('[EQW_LayoutSolver] attach target=' + targetKey + '(' + mode + ')需要数字 w:配置未写 w,且 ctx.w 未给出');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_requireH: function (n, targetKey, mode) {
|
_requireH: function (h, targetKey, mode) {
|
||||||
if (typeof n.h !== 'number') {
|
if (typeof h !== 'number') {
|
||||||
throw new Error('[EQW_LayoutSolver] attach target=' + targetKey + '(' + mode + ')需要数字 h,当前缺失');
|
throw new Error('[EQW_LayoutSolver] attach target=' + targetKey + '(' + mode + ')需要数字 h:配置未写 h,且 ctx.h 未给出');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,41 @@ t.eq('attach corner=bottomRight 缺 w 抛错',
|
|||||||
t.eq('attach corner=bottomRight 缺 h 抛错',
|
t.eq('attach corner=bottomRight 缺 h 抛错',
|
||||||
throws(() => EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: 'bottomRight', w: 20 }, { rects: rects })), true);
|
throws(() => EQW_LayoutSolver.solve({ kind: 'attach', target: 'TARGET', corner: 'bottomRight', w: 20 }, { rects: rects })), true);
|
||||||
|
|
||||||
|
// ============ attach w/h 运行时注入(ctx.w/ctx.h,供动态文字标签/牌角标等尺寸未知的模板节点用)============
|
||||||
|
// 配置无 w、hAlign=right(用得到 sprite.width)、靠 ctx.w 补上 → 正常求解,返回 width 就是 ctx.w
|
||||||
|
const wFromCtx = EQW_LayoutSolver.solve(
|
||||||
|
{ kind: 'attach', target: 'TARGET', hAlign: 'right', vAlign: 'top', h: 10 },
|
||||||
|
{ rects: rects, w: 42 }
|
||||||
|
);
|
||||||
|
t.eq('ctx.w 补全缺失的 w,正常求解', throws(() => EQW_LayoutSolver.solve(
|
||||||
|
{ kind: 'attach', target: 'TARGET', hAlign: 'right', vAlign: 'top', h: 10 }, { rects: rects, w: 42 }
|
||||||
|
)), false);
|
||||||
|
t.eq('返回的 width 等于 ctx.w', wFromCtx[0].width, 42);
|
||||||
|
|
||||||
|
// 配置有 w,同时给 ctx.w → ctx.w 优先覆盖配置值
|
||||||
|
const wOverride = EQW_LayoutSolver.solve(
|
||||||
|
{ kind: 'attach', target: 'TARGET', hAlign: 'right', vAlign: 'top', w: 20, h: 10 },
|
||||||
|
{ rects: rects, w: 99 }
|
||||||
|
);
|
||||||
|
t.eq('ctx.w 覆盖配置里的 w', wOverride[0].width, 99);
|
||||||
|
|
||||||
|
// 配置无 h、vAlign=middle(用得到 sprite.height)、靠 ctx.h 补上 → 正常求解,返回 height 就是 ctx.h
|
||||||
|
const hFromCtx = EQW_LayoutSolver.solve(
|
||||||
|
{ kind: 'attach', target: 'TARGET', hAlign: 'left', vAlign: 'middle', w: 20 },
|
||||||
|
{ rects: rects, h: 33 }
|
||||||
|
);
|
||||||
|
t.eq('返回的 height 等于 ctx.h', hFromCtx[0].height, 33);
|
||||||
|
|
||||||
|
// 配置无 w、hAlign=right、ctx.w 也没给 → 仍然抛错(不能因为加了通道就失效)
|
||||||
|
t.eq('两处都没给 w 仍抛错', throws(() => EQW_LayoutSolver.solve(
|
||||||
|
{ kind: 'attach', target: 'TARGET', hAlign: 'right', vAlign: 'top', h: 10 }, { rects: rects }
|
||||||
|
)), true);
|
||||||
|
|
||||||
|
// ctx.w/ctx.h 对不需要该维度的对齐模式(hAlign=left)不产生影响,仍正常求解
|
||||||
|
t.eq('hAlign=left 时给不给 ctx.w 都不影响', throws(() => EQW_LayoutSolver.solve(
|
||||||
|
{ kind: 'attach', target: 'TARGET', hAlign: 'left', vAlign: 'top' }, { rects: rects, w: 7 }
|
||||||
|
)), false);
|
||||||
|
|
||||||
// ============ attach target 运行时注入(ctx.target,供叫分档位/花色图标/牌角标等模板节点用)============
|
// ============ attach target 运行时注入(ctx.target,供叫分档位/花色图标/牌角标等模板节点用)============
|
||||||
const rects2 = { TARGET: { x: 100, y: 200, width: 80, height: 40 }, OTHER: { x: 5, y: 6, width: 10, height: 10 } };
|
const rects2 = { TARGET: { x: 100, y: 200, width: 80, height: 40 }, OTHER: { x: 5, y: 6, width: 10, height: 10 } };
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user