Compare commits
14 Commits
3a765e01a8
...
85e5979414
| Author | SHA1 | Date | |
|---|---|---|---|
| 85e5979414 | |||
| c7c1823594 | |||
| f40f3b8425 | |||
| 69e426d9ce | |||
| 4f7f47dc1c | |||
| 40a7d87832 | |||
| 433c4e6a75 | |||
| eb3e206006 | |||
| 3005465d1d | |||
| 0a55bba1c9 | |||
| b4c0799676 | |||
| a39c7216b3 | |||
| 59ba29e5a0 | |||
| 31b326b090 |
@@ -9,7 +9,40 @@
|
|||||||
toCobiets
|
toCobiets
|
||||||
} = window.Cobie;
|
} = window.Cobie;
|
||||||
|
|
||||||
// CoBiE helpers pulled from cobie.js
|
function getMarkerOffset(width) {
|
||||||
|
const points = [
|
||||||
|
{ width: 1024, value: 2 },
|
||||||
|
{ width: 450, value: 1.3 },
|
||||||
|
{ width: 200, value: 0.8 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sort points by width descending for easier handling
|
||||||
|
points.sort((a, b) => b.width - a.width);
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length - 1; i++) {
|
||||||
|
const p1 = points[i];
|
||||||
|
const p2 = points[i + 1];
|
||||||
|
if (width <= p1.width && width >= p2.width) {
|
||||||
|
// Linear interpolation
|
||||||
|
const t = (width - p2.width) / (p1.width - p2.width);
|
||||||
|
return p2.value + t * (p1.value - p2.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extrapolation for width > max known
|
||||||
|
if (width > points[0].width) {
|
||||||
|
const p1 = points[0];
|
||||||
|
const p2 = points[1];
|
||||||
|
const slope = (p1.value - p2.value) / (p1.width - p2.width);
|
||||||
|
return p1.value + slope * (width - p1.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extrapolation for width < min known
|
||||||
|
const p1 = points[points.length - 2];
|
||||||
|
const p2 = points[points.length - 1];
|
||||||
|
const slope = (p2.value - p1.value) / (p2.width - p1.width);
|
||||||
|
return p2.value + slope * (width - p2.width);
|
||||||
|
}
|
||||||
|
|
||||||
function placeMarkers() {
|
function placeMarkers() {
|
||||||
const clock = document.getElementById('clock');
|
const clock = document.getElementById('clock');
|
||||||
@@ -40,38 +73,38 @@
|
|||||||
ticks = clock.querySelectorAll('.tick');
|
ticks = clock.querySelectorAll('.tick');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position markers based on the current clock size
|
// Unified radius based on the actual clock size
|
||||||
// Move markers slightly inward and tweak the center position so
|
const baseRadius = clock.offsetWidth / 2;
|
||||||
// the ring of ticks lines up perfectly with the border.
|
|
||||||
const borderOffset = clock.offsetWidth > 300 ? 45 : 26;
|
// Tick lengths relative to the clock radius
|
||||||
const centerAdjust = { x: -3, y: -2 };
|
const lenBig = baseRadius * 0.12;
|
||||||
const markerRadius = clock.offsetWidth / 2 - borderOffset;
|
const lenMid = baseRadius * 0.08;
|
||||||
|
const lenSmall = baseRadius * 0.05;
|
||||||
|
|
||||||
|
const outerR = baseRadius - 2; // just inside the border
|
||||||
|
|
||||||
|
// Distance from center for the marker digits so they sit just inside big ticks
|
||||||
|
const markerSize = markers[0] ? markers[0].offsetWidth : 0;
|
||||||
|
const markerRadius = outerR - lenBig - markerSize * getMarkerOffset(clock.offsetWidth);
|
||||||
|
|
||||||
markers.forEach((m, i) => {
|
markers.forEach((m, i) => {
|
||||||
const angle = (i / 16) * 2 * Math.PI;
|
const angle = (i / 16) * 2 * Math.PI;
|
||||||
const x = markerRadius * Math.sin(angle);
|
m.style.left = '50%';
|
||||||
const y = -markerRadius * Math.cos(angle);
|
m.style.top = '50%';
|
||||||
m.style.left = `${clock.offsetWidth / 2 + x + centerAdjust.x}px`;
|
m.style.transform =
|
||||||
m.style.top = `${clock.offsetHeight / 2 + y + centerAdjust.y}px`;
|
`translate(-50%, -50%) rotate(${angle}rad) translate(0, -${markerRadius}px) rotate(${-angle}rad)`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tick lengths based on the marker radius
|
|
||||||
const lenBig = markerRadius * 0.12;
|
|
||||||
const lenMid = markerRadius * 0.08;
|
|
||||||
const lenSmall = markerRadius * 0.05;
|
|
||||||
|
|
||||||
ticks.forEach((t, i) => {
|
ticks.forEach((t, i) => {
|
||||||
let len = lenSmall;
|
let len = lenSmall;
|
||||||
if (t.classList.contains('big')) len = lenBig;
|
if (t.classList.contains('big')) len = lenBig;
|
||||||
else if (t.classList.contains('mid')) len = lenMid;
|
else if (t.classList.contains('mid')) len = lenMid;
|
||||||
const outerR = clock.offsetWidth / 2 - 2;
|
|
||||||
const innerR = outerR - len;
|
const innerR = outerR - len;
|
||||||
const angle = (i / 256) * 2 * Math.PI;
|
const angle = ((i + 1) / 256) * 2 * Math.PI;
|
||||||
const x = innerR * Math.sin(angle);
|
|
||||||
const y = -innerR * Math.cos(angle);
|
|
||||||
t.style.height = `${len}px`;
|
t.style.height = `${len}px`;
|
||||||
t.style.left = `${clock.offsetWidth / 2 + x - t.offsetWidth / 2 + centerAdjust.x}px`;
|
t.style.left = '50%';
|
||||||
t.style.top = `${clock.offsetHeight / 2 + y + centerAdjust.y}px`;
|
t.style.top = '50%';
|
||||||
t.style.transform = `rotate(${angle}rad)`;
|
t.style.transform = `translate(-50%, 0) rotate(${angle}rad) translate(0, -${innerR}px)`;
|
||||||
if (clock.offsetWidth < 200 && !t.classList.contains('big') && !t.classList.contains('mid')) {
|
if (clock.offsetWidth < 200 && !t.classList.contains('big') && !t.classList.contains('mid')) {
|
||||||
t.style.display = 'none';
|
t.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
@@ -101,14 +134,14 @@
|
|||||||
el.removeEventListener('transitionend', handle);
|
el.removeEventListener('transitionend', handle);
|
||||||
// Snap back without animation
|
// Snap back without animation
|
||||||
el.style.transition = 'none';
|
el.style.transition = 'none';
|
||||||
el.style.transform = `rotate(${angle}deg)`;
|
el.style.transform = `translateX(-50%) rotate(${angle}deg)`;
|
||||||
void el.offsetWidth;
|
void el.offsetWidth;
|
||||||
el.style.transition = '';
|
el.style.transition = '';
|
||||||
};
|
};
|
||||||
el.addEventListener('transitionend', handle, { once: true });
|
el.addEventListener('transitionend', handle, { once: true });
|
||||||
el.style.transform = `rotate(${target}deg)`;
|
el.style.transform = `translateX(-50%) rotate(${target}deg)`;
|
||||||
} else {
|
} else {
|
||||||
el.style.transform = `rotate(${angle}deg)`;
|
el.style.transform = `translateX(-50%) rotate(${angle}deg)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastAngles[id] = angle;
|
lastAngles[id] = angle;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 40vmin;
|
height: var(--clock-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-time.manual::before {
|
.current-time.manual::before {
|
||||||
@@ -360,6 +360,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.eonstrip-grid {
|
.eonstrip-grid {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
@@ -369,6 +370,7 @@
|
|||||||
|
|
||||||
/* Layout combining current time and analog clock */
|
/* Layout combining current time and analog clock */
|
||||||
.time-display {
|
.time-display {
|
||||||
|
--clock-size: 40vmin;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@@ -378,7 +380,6 @@
|
|||||||
|
|
||||||
|
|
||||||
.analog-clock-container {
|
.analog-clock-container {
|
||||||
--clock-size: 40vmin;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: var(--clock-size);
|
width: var(--clock-size);
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@@ -414,11 +415,11 @@
|
|||||||
|
|
||||||
.clock-label {
|
.clock-label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 23%;
|
bottom: 30%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
font-family: 'Great Vibes', cursive;
|
font-family: 'Great Vibes', cursive;
|
||||||
font-size: calc(var(--clock-size) * 0.08);
|
font-size: calc(var(--clock-size) * 0.06);
|
||||||
color: #ffaaff;
|
color: #ffaaff;
|
||||||
text-shadow: 0 0 6px rgba(255, 0, 255, 0.6);
|
text-shadow: 0 0 6px rgba(255, 0, 255, 0.6);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@@ -445,7 +446,11 @@ body.fullscreen-clock .clock-label {
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
text-shadow: 0 0 6px rgba(0, 255, 255, 0.9), 0 0 12px rgba(0, 255, 255, 0.7);
|
text-shadow: 0 0 6px rgba(0, 255, 255, 0.9), 0 0 12px rgba(0, 255, 255, 0.7);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
transform: translate(-50%, -50%);
|
transform-origin: center;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
will-change: transform;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +474,8 @@ body.fullscreen-clock .clock-label {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 50%;
|
bottom: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform-origin: bottom;
|
transform-origin: bottom center;
|
||||||
|
transform: translateX(-50%);
|
||||||
transition: transform 0.5s ease-in-out;
|
transition: transform 0.5s ease-in-out;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@@ -478,39 +484,46 @@ body.fullscreen-clock .clock-label {
|
|||||||
|
|
||||||
.hand.xeno {
|
.hand.xeno {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
height: 42%;
|
height: 44%;
|
||||||
background: linear-gradient(to top, #66ccff, #0044ff);
|
background: linear-gradient(to top, #66ccff, #0044ff);
|
||||||
box-shadow: 0 0 8px #66ccff;
|
box-shadow: 0 0 8px #66ccff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hand.quantic {
|
.hand.quantic {
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 36%;
|
height: 40%;
|
||||||
background: linear-gradient(to top, #ff66ff, #9900ff);
|
background: linear-gradient(to top, #ff66ff, #9900ff);
|
||||||
box-shadow: 0 0 8px #ff66ff;
|
box-shadow: 0 0 8px #ff66ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hand.chronon {
|
.hand.chronon {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 32%;
|
height: 34%;
|
||||||
background: linear-gradient(to top, #ff4444, #880000);
|
background: linear-gradient(to top, #ff4444, #880000);
|
||||||
box-shadow: 0 0 8px #ff4444;
|
box-shadow: 0 0 8px #ff4444;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hand.eonstrip {
|
.hand.eonstrip {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 22%;
|
height: 30%;
|
||||||
background: linear-gradient(to top, #33ff99, #006633);
|
background: linear-gradient(to top, #33ff99, #006633);
|
||||||
box-shadow: 0 0 8px #33ff99;
|
box-shadow: 0 0 8px #33ff99;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.hand.megasequence {
|
.hand.megasequence {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 18%;
|
height: 26%;
|
||||||
background: linear-gradient(to top, #ffbb33, #aa5500);
|
background: linear-gradient(to top, #ffbb33, #aa5500);
|
||||||
box-shadow: 0 0 8px #ffbb33;
|
box-shadow: 0 0 8px #ffbb33;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-height: 430px) and (orientation: landscape) {
|
||||||
|
.time-display {
|
||||||
|
--clock-size: 70vmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
body.fullscreen-clock .header,
|
body.fullscreen-clock .header,
|
||||||
body.fullscreen-clock .current-time,
|
body.fullscreen-clock .current-time,
|
||||||
body.fullscreen-clock .timezone-selector,
|
body.fullscreen-clock .timezone-selector,
|
||||||
|
|||||||
Reference in New Issue
Block a user