Files
ClockLab/test/resize.test.js
T
AskaEth 9c7081b21d feat: ClockLab —— 可调速桌面时钟(数字/表盘,支持倍率、暂停、倒转、快进)
一个用于演练/演示的桌面时钟工具:两个窗口 —— 控制窗口(普通)与时钟窗口(无边框、
可拖动、可拖边缘改大小,由控制窗口开与关)。

功能
- 两个窗口各自的「始终置顶」开关
- 显示样式:纯数字 / 圆形表盘,切换立即生效
- 实时设定时间(含「填入当前显示时间」)
- 倍率:支持正数、负数(倒转)、0(暂停)、小数
- 暂停 / 继续(继续时回到暂停前的倍率,按钮文案会显示是几倍)
- 快进五档:+5 秒 / +1 分钟 / +5 分钟 / +10 分钟 / +30 分钟

实现要点
- 走时是「基准时间 + 基准时刻 + 倍率」的锚点式模型(不累加、零漂移);
  倍率、暂停、倒转、快进因此是同一套机制的四个用法,互不打架
- 跳转动画做在「呈现时间」这一层:数字滚动与表盘指针扫动共用同一个中间值,
  所以永远同步,也不会跨 12 点倒着转一圈
- 无边框窗口的拖动(CSS app-region + 控件 no-drag)与拖边缘改大小
  (自己算几何 + IPC setBounds,因为 frame:false 下系统边缘命中不可靠)

测试 152 例:走时模型 / 改大小几何 / 呈现时间 / 两个渲染进程(DOM 桩)
2026-09-15 01:31:07 +08:00

83 lines
3.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
// 拖边缘改大小的几何用例(纯计算,不需要 Electron):
// node test/resize.test.js
// 无边框窗口里这段代码只有真鼠标拖拽才能触发,先用纯函数把它钉死,Windows 上就只剩「手感」要试。
const { computeBounds, MIN_SIZE } = require('../renderer/resize');
let passed = 0;
const failures = [];
function check(name, ok, detail) {
if (ok) {
passed += 1;
console.log(`PASS ${name}${detail ? ` [${detail}]` : ''}`);
} else {
failures.push(name);
console.log(`FAIL ${name}${detail ? ` [${detail}]` : ''}`);
}
}
const start = { x: 400, y: 300, width: 520, height: 280 };
const same = (a, b) => a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
console.log('--- 单边 ---');
check('东边 +120:只有宽度变,左上角不动',
same(computeBounds(start, 'e', 120, 0), { x: 400, y: 300, width: 640, height: 280 }));
check('南边 +60:只有高度变',
same(computeBounds(start, 's', 0, 60), { x: 400, y: 300, width: 520, height: 340 }));
check('西边 -80:宽度增加 80,左边界左移 80',
same(computeBounds(start, 'w', -80, 0), { x: 320, y: 300, width: 600, height: 280 }));
check('北边 -50:高度增加 50,上边界上移 50',
same(computeBounds(start, 'n', 0, -50), { x: 400, y: 250, width: 520, height: 330 }));
check('东边往回拖 -100:窗口变窄,左上角不动',
same(computeBounds(start, 'e', -100, 0), { x: 400, y: 300, width: 420, height: 280 }));
console.log('--- 四角 ---');
check('右下角 +40/+30:宽高同时增加',
same(computeBounds(start, 'se', 40, 30), { x: 400, y: 300, width: 560, height: 310 }));
check('左上角 -40/-30:宽高增加且整体左上移',
same(computeBounds(start, 'nw', -40, -30), { x: 360, y: 270, width: 560, height: 310 }));
check('右上角 +40/-30:宽度增加、上边界上移',
same(computeBounds(start, 'ne', 40, -30), { x: 400, y: 270, width: 560, height: 310 }));
check('左下角 -40/+30:左边界左移、高度增加',
same(computeBounds(start, 'sw', -40, 30), { x: 360, y: 300, width: 560, height: 310 }));
console.log('--- 最小尺寸 ---');
check('东边往死里拖:宽度停在 260', computeBounds(start, 'e', -9999, 0).width === MIN_SIZE.width);
check('南边往死里拖:高度停在 150', computeBounds(start, 's', 0, -9999).height === MIN_SIZE.height);
{
const r = computeBounds(start, 'w', 9999, 0);
check('西边往死里拖:宽度停在 260,且右边界不动(窗口不会被推走)',
r.width === MIN_SIZE.width && r.x + r.width === start.x + start.width, JSON.stringify(r));
}
{
const r = computeBounds(start, 'n', 0, 9999);
check('北边往死里拖:高度停在 150,且下边界不动',
r.height === MIN_SIZE.height && r.y + r.height === start.y + start.height, JSON.stringify(r));
}
{
const r = computeBounds(start, 'nw', 9999, 9999);
check('左上角往死里拖:宽高都停在最小值,右下角不动',
r.width === MIN_SIZE.width && r.height === MIN_SIZE.height &&
r.x + r.width === start.x + start.width && r.y + r.height === start.y + start.height, JSON.stringify(r));
}
console.log('--- 边界 ---');
check('位移为 0 时原样返回', same(computeBounds(start, 'e', 0, 0), start));
check('结果都是整数(避免 setBounds 收到小数后抖动)',
Number.isInteger(computeBounds(start, 'e', 12.4, 0).width));
check('负坐标(窗口在主屏左侧)也能算',
same(computeBounds({ x: -900, y: -200, width: 520, height: 280 }, 'w', -100, 0),
{ x: -1000, y: -200, width: 620, height: 280 }));
console.log('');
if (failures.length === 0) {
console.log(`全部通过:${passed}/${passed}`);
process.exit(0);
} else {
console.log(`通过 ${passed},失败 ${failures.length}:${failures.join(';')}`);
process.exit(1);
}