如何将方形时钟的刻度线排列到方形边缘?
数据小许
结论
现有刻度线以 transform-origin: 50% 50cqi 为旋转中心,旋转半径固定,所以排列成圆形。要让 60 条刻度线沿正方形边缘分布,需要根据每条刻度的角度计算它与正方形边界的交点,再设置刻度线的位置和旋转角度。
下面的代码从时钟中心出发,计算每条刻度线到正方形边缘的距离,并每隔 5 条设置一条较长的主刻度。
CSS
用以下规则替换原有的 .diallines 和 .diallines:nth-of-type(5n) 定位规则:
.diallines {
position: absolute;
z-index: 2;
top: 0;
left: 0;
width: 0.67cqi;
height: 5cqi;
margin: 0;
background: #666;
transform-origin: center;
}
.diallines.major {
width: 1.33cqi;
height: 8.33cqi;
}
:nth-of-type(5n) 根据同级元素的标签位置匹配,不能保证选中每第五条 .diallines。这里由 JavaScript 为主刻度添加 .major 类。
JavaScript
替换原先创建刻度线的循环。下面的代码会先移除 HTML 中已有的刻度线,再创建 60 条新刻度线:
var clockEl = document.querySelector('.clock');
clockEl.querySelectorAll('.diallines').forEach(function (line) {
line.remove();
});
for (var i = 0; i < 60; i++) {
var angle = i * 6;
var radians = angle * Math.PI / 180;
var sin = Math.sin(radians);
var cos = Math.cos(radians);
var line = document.createElement('div');
line.className = i % 5 === 0 ? 'diallines major' : 'diallines';
clockEl.appendChild(line);
var tickLength = line.getBoundingClientRect().height;
var half = Math.min(clockEl.clientWidth, clockEl.clientHeight) / 2;
var edgeDistance = half / Math.max(Math.abs(sin), Math.abs(cos));
var radius = edgeDistance - tickLength / 2;
line.style.left = (clockEl.clientWidth / 2 + sin * radius) + 'px';
line.style.top = (clockEl.clientHeight / 2 - cos * radius) + 'px';
line.style.transform =
'translate(-50%, -50%) rotate(' + angle + 'deg)';
}
Math.max(Math.abs(sin), Math.abs(cos)) 根据方向计算射线到正方形边界的距离。当刻度角度为 45deg、135deg 等时,交点会落在正方形的角上。减去刻度线长度的一半后,刻度线会以交点为中心。若要让刻度线完全位于边缘内侧,可以再从 radius 中减去一小段距离。
让时钟尽可能占满视口
如果“占满”是指尽量利用浏览器视口,同时保持时钟为正方形,可以给 .clock 设置:
.clock {
width: min(100vw, 100vh);
height: auto;
aspect-ratio: 1 / 1;
box-sizing: border-box;
}
时钟尺寸会根据视口较短的一边确定。若时钟需要适配其他容器,可以将 100vw 和 100vh 换成容器的可用尺寸。
时钟尺寸变化后,需要重新计算刻度位置,例如在窗口尺寸变化时再次运行生成刻度的逻辑。上述代码假设 .clock 是正方形,并且刻度线由这段 JavaScript 重新生成。
备注:内容仅供参考。
