From 743d9fba9e6e276e809ed2949118144e30a23ee4 Mon Sep 17 00:00:00 2001 From: sthag Date: Sat, 28 Feb 2026 11:27:23 +0100 Subject: [PATCH 01/19] feat: Update clock - Update resizeClock() - Change background of groups --- source/screens/demo/examples/clock.liquid | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index a4bd20d..d518436 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -39,9 +39,6 @@ tags: let centerX = canvasRings.width / 2; let centerY = canvasRings.height / 2; let maxSize = (canvasRings.width / 2 - ringWidth / 2) - outerMargin; - - resizeClock(); - const rings = [ { radius: maxSize, @@ -75,22 +72,22 @@ tags: const groups = [ { radius: rings[1].radius, - color: `rgba(0, 0, 0, .1)`, + color: `rgba(0, 0, 0, .05)`, width: 72 }, { radius: rings[3].radius, - color: `rgba(0, 0, 0, .2)`, + color: `rgba(0, 0, 0, .1)`, width: ringWidth + ringGap }, { radius: rings[4].radius, - color: `rgba(0, 0, 0, .3)`, + color: `rgba(0, 0, 0, .15)`, width: ringWidth + ringGap }, { radius: maxSize - (ringWidth + ringGap) * 6 - ringGap - ringGap / 2, - color: `rgba(0, 0, 0, .4)`, + color: `rgba(0, 0, 0, .2)`, width: ringWidth * 2 + ringGap * 2 } ]; @@ -148,8 +145,7 @@ tags: // FIXME: Konstanten mit maxSize werden nicht verändert window.addEventListener('resize', resizeClock); - drawBackground(); - updateRings(); + resizeClock(); // TODO: TimeDisplay nutzen, ev. erweitern oder ähnliche Umsetzung anwenden setInterval(updateRings, 1000); @@ -293,5 +289,8 @@ tags: console.debug('Clock size: ', clockSize); console.debug('Radius: ', maxSize); } + drawBackground(); + updateRings(); + } {% endblock %} \ No newline at end of file From 62b21b5e68646c6a509a67ed001cef19335fde5e Mon Sep 17 00:00:00 2001 From: sthag Date: Sat, 28 Feb 2026 11:31:57 +0100 Subject: [PATCH 02/19] feat: New class HippieClock Adapt everything to a class based prototype. - Functionality of clock still missing - Original version is hidden - Size now is dynamic - Parts can be added --- source/screens/demo/examples/clock.liquid | 133 +++++++++++++++++++++- source/style/modules/_clock.scss | 11 +- 2 files changed, 135 insertions(+), 9 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index d518436..4bb0a32 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -285,12 +285,137 @@ tags: wrap.style.width = clockSize + 'px'; wrap.style.height = clockSize + 'px'; - console.debug(windowDimension); - console.debug('Clock size: ', clockSize); - console.debug('Radius: ', maxSize); - } drawBackground(); updateRings(); } + + class HippieClock { + constructor(element, options) { + this.element = element; + this.shapes = []; + this.id = null; + this.options = options || { + size: Math.floor(this.getSize().value * 0.9) + }; + this.parts = this.createContext(['bkg', 'hands']); + + this.init(); + } + + init() { + // TODO: shapes[] ist zu diesem Zeitpunkt noch leer + this.resize(); + window.addEventListener('resize', () => this.resize()); + } + + resize() { + this.parts.forEach(part => { + part.element.width = part.element.offsetWidth; + part.element.height = part.element.offsetHeight; + this.draw(); + }); + } + + draw() { + this.parts.forEach(part => { + part.context.clearRect(0, 0, part.element.width, part.element.height); + }); + + this.shapes.forEach(shape => { + if (shape.type === 'circle') { + const radius = this.toPixelSize(shape.radius) / 2; + + this.parts[0].context.fillStyle = shape.color; + this.parts[0].context.beginPath(); + this.parts[0].context.arc( + this.toPixelX(shape.center), + this.toPixelY(shape.center), + radius, + 0, + Math.PI * 2 + ); + this.parts[0].context.fill(); + } else if (shape.type === 'ring') { + const radius = this.toPixelSize(shape.radius) / 2 - shape.stroke / 2; + + this.parts[1].context.strokeStyle = shape.color; + this.parts[1].context.lineWidth = shape.stroke; + this.parts[1].context.beginPath(); + this.parts[1].context.arc( + this.toPixelX(shape.center), + this.toPixelY(shape.center), + radius, + 0, + Math.PI * 2 + ); + this.parts[1].context.stroke(); + } + }); + } + + toPixelX(number) { + return number * this.parts[0].element.width; + } + + toPixelY(number) { + return number * this.parts[0].element.height; + } + + toPixelSize(number) { + return number * Math.min(this.parts[0].element.width, this.parts[0].element.height); + } + + getSize() { + const height = window.innerHeight; + const width = window.innerWidth; + + return { + value: Math.min(height, width), + smaller: height < width ? 'height' : 'width' + }; + } + + createContext(names) { + let parts = []; + const wrap = document.createElement('div'); + wrap.style.position = 'relative'; + wrap.style.height = this.options.size + 'px'; + wrap.style.width = this.options.size + 'px'; + + names.forEach(name => { + const canvas = document.createElement('canvas'); + + canvas.style.position = 'absolute'; + canvas.style.top = '0px'; + canvas.style.left = '0px'; + canvas.style.height = '100%'; + canvas.style.width = '100%'; + canvas.height = canvas.offsetHeight; + canvas.width = canvas.offsetWidth; + + wrap.appendChild(canvas); + + parts.push({name: name, element: canvas, context: canvas.getContext('2d')}); + }); + + this.element.appendChild(wrap); + + return parts; + } + + addCircle(id, center, radius, color = `rgba(0, 0, 0, .1)`) { + this.shapes.push({type: 'circle', id, center, radius, color}); + } + + addRing(id, center, radius, color = `rgb(250, 216, 3)`, stroke = 16) { + this.shapes.push({type: 'ring', id, center, radius, color, stroke}); + } + } + + const container = document.querySelector('#clock main'); + const clock = new HippieClock(container); + clock.addCircle('base', .5, 1); + clock.addRing('seconds', .5, 1); + clock.draw(); {% endblock %} \ No newline at end of file diff --git a/source/style/modules/_clock.scss b/source/style/modules/_clock.scss index 4caa66e..4674e4b 100644 --- a/source/style/modules/_clock.scss +++ b/source/style/modules/_clock.scss @@ -24,13 +24,14 @@ } .wrap { + display: none; position: relative; - } - canvas { - position: absolute; - top: 0; - left: 0; + canvas { + position: absolute; + top: 0; + left: 0; + } } p { From 667269e4e7d822ca7defd21d8fdec6186900cbf4 Mon Sep 17 00:00:00 2001 From: sthag Date: Sat, 28 Feb 2026 18:56:21 +0100 Subject: [PATCH 03/19] feat: Update HippieClock - Add update possibility - Ring now has start and angle - Date functions added to class --- source/screens/demo/examples/clock.liquid | 71 ++++++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 4bb0a32..ff28d37 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -290,14 +290,14 @@ tags: } class HippieClock { - constructor(element, options) { + constructor(element, date, options) { this.element = element; - this.shapes = []; - this.id = null; + this.date = this.getTime(date); this.options = options || { size: Math.floor(this.getSize().value * 0.9) }; this.parts = this.createContext(['bkg', 'hands']); + this.shapes = []; this.init(); } @@ -317,6 +317,7 @@ tags: } draw() { + // TODO: Nur geänderte Teile löschen this.parts.forEach(part => { part.context.clearRect(0, 0, part.element.width, part.element.height); }); @@ -337,6 +338,8 @@ tags: this.parts[0].context.fill(); } else if (shape.type === 'ring') { const radius = this.toPixelSize(shape.radius) / 2 - shape.stroke / 2; + const start = -0.5 * Math.PI; // Start at the top + const angle = start + (2 * Math.PI * (shape.angle / shape.max)); this.parts[1].context.strokeStyle = shape.color; this.parts[1].context.lineWidth = shape.stroke; @@ -345,14 +348,21 @@ tags: this.toPixelX(shape.center), this.toPixelY(shape.center), radius, - 0, - Math.PI * 2 + start, + angle ); this.parts[1].context.stroke(); } }); } + update() { + const second = this.getTime().second; + + this.updateShape('seconds', (second === 0) ? 60 : second); + this.draw(); + } + toPixelX(number) { return number * this.parts[0].element.width; } @@ -365,6 +375,23 @@ tags: return number * Math.min(this.parts[0].element.width, this.parts[0].element.height); } + // TODO: Parameter für Wochenstart ergänzen + getNumericWeekday(date) { + const weekday = date.getDay(); // 0 (Sunday) to 6 (Saturday) + + return (weekday === 0) ? 7 : weekday; + } + + getNumericYearDay(date) { + const start = new Date(date.getFullYear(), 0, 0); + + return Math.floor((date - start) / 86400000); + } + + daysInMonth(month, year) { + return new Date(year, month, 0).getDate(); + } + getSize() { const height = window.innerHeight; const width = window.innerWidth; @@ -375,9 +402,25 @@ tags: }; } + getTime(date) { + this.date = date || new Date(); + + return { + second: this.date.getSeconds(), + minute: this.date.getMinutes(), + hour: this.date.getHours(), + dayOfWeek: getNumericWeekday(this.date), + dayOfMonth: this.date.getDate(), + dayOfYear: getNumericYearDay(this.date), + month: this.date.getMonth() + 1, // Get current month (0-11) + daysInMonth: this.daysInMonth(this.date.getMonth() + 1, this.date.getFullYear()) + }; + } + createContext(names) { let parts = []; const wrap = document.createElement('div'); + wrap.style.position = 'relative'; wrap.style.height = this.options.size + 'px'; wrap.style.width = this.options.size + 'px'; @@ -403,19 +446,31 @@ tags: return parts; } + updateShape(id, value) { + const shape = this.shapes.find(s => s.id === id); + + if (shape) { + shape.angle = value; + } + } + addCircle(id, center, radius, color = `rgba(0, 0, 0, .1)`) { this.shapes.push({type: 'circle', id, center, radius, color}); } - addRing(id, center, radius, color = `rgb(250, 216, 3)`, stroke = 16) { - this.shapes.push({type: 'ring', id, center, radius, color, stroke}); + addRing(id, center, radius, angle, max, color = `rgb(250, 216, 3)`, stroke = 16) { + this.shapes.push({type: 'ring', id, center, radius, angle, max, color, stroke}); } } const container = document.querySelector('#clock main'); const clock = new HippieClock(container); clock.addCircle('base', .5, 1); - clock.addRing('seconds', .5, 1); + clock.addRing('seconds', .5, 1, 0, 60); clock.draw(); + + setInterval(() => { + clock.update(); + }, 1000); {% endblock %} \ No newline at end of file From ad135a58c10c25423b00c7ec5bab929c8bdb1a7f Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 08:47:12 +0100 Subject: [PATCH 04/19] feat: Update HippieClock - Add all rings - Add 24/12 hour switch - Options can now be updated - Add max to updateShape() - Change attributes for addRing() --- source/screens/demo/examples/clock.liquid | 58 ++++++++++++++++++----- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index ff28d37..a3690ff 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -8,7 +8,7 @@ tags: {% block body %}
- +
@@ -294,7 +294,8 @@ tags: this.element = element; this.date = this.getTime(date); this.options = options || { - size: Math.floor(this.getSize().value * 0.9) + size: Math.floor(this.getSize().value * 0.9), + h24: true }; this.parts = this.createContext(['bkg', 'hands']); this.shapes = []; @@ -303,9 +304,18 @@ tags: } init() { - // TODO: shapes[] ist zu diesem Zeitpunkt noch leer + this.addRing('seconds', 1, 21, 60, `rgb(250, 216, 3)`); + this.addRing('minutes', .9, 46, 60, `rgb(242, 175, 19)`); + this.addRing('minutes', .8, 6, this.options.h24 ? 24 : 12, `rgb(211, 10, 81)`); + this.addRing('dotweek', .7, 32, 7, `rgb(142, 31, 104)`); + this.addRing('dotmonth', .6, 12, this.getTime().daysMonth, `rgb(39, 63, 139)`); + this.addRing('dotyear', .5, 256, 365, `rgb(60, 87, 154)`); + this.addRing('month', .4, 10, 12, `rgb(183, 224, 240)`); + this.resize(); window.addEventListener('resize', () => this.resize()); + + console.debug(this); } resize() { @@ -358,8 +368,16 @@ tags: update() { const second = this.getTime().second; + const minute = this.getTime().minute; + const hour = this.getTime().hour; this.updateShape('seconds', (second === 0) ? 60 : second); + this.updateShape('minutes', (minute === 0) ? 60 : minute); + this.updateShape('hours', this.options.h24 ? hour : hour % 12, this.options.h24 ? 24 : 12); + this.updateShape('dotweek', this.getTime().dayWeek); + this.updateShape('dotmonth', this.getTime().dayMonth, this.getTime().daysMonth); + this.updateShape('dotyear', this.getTime().dayYear); + this.updateShape('month', this.getTime().month); this.draw(); } @@ -409,11 +427,11 @@ tags: second: this.date.getSeconds(), minute: this.date.getMinutes(), hour: this.date.getHours(), - dayOfWeek: getNumericWeekday(this.date), - dayOfMonth: this.date.getDate(), - dayOfYear: getNumericYearDay(this.date), + dayWeek: this.getNumericWeekday(this.date), + dayMonth: this.date.getDate(), + dayYear: this.getNumericYearDay(this.date), month: this.date.getMonth() + 1, // Get current month (0-11) - daysInMonth: this.daysInMonth(this.date.getMonth() + 1, this.date.getFullYear()) + daysMonth: this.daysInMonth(this.date.getMonth() + 1, this.date.getFullYear()) }; } @@ -446,31 +464,47 @@ tags: return parts; } - updateShape(id, value) { + updateShape(id, angle, max) { const shape = this.shapes.find(s => s.id === id); if (shape) { - shape.angle = value; + shape.angle = angle; + if (max) shape.max = max; } } + updateOptions(changes) { + this.options = {...this.options, ...changes}; + } + addCircle(id, center, radius, color = `rgba(0, 0, 0, .1)`) { this.shapes.push({type: 'circle', id, center, radius, color}); } - addRing(id, center, radius, angle, max, color = `rgb(250, 216, 3)`, stroke = 16) { - this.shapes.push({type: 'ring', id, center, radius, angle, max, color, stroke}); + addRing(id, radius, angle, max, color = 'black', center = .5, stroke = 16) { + this.shapes.push({type: 'ring', id, radius, angle, max, color, center, stroke}); } } const container = document.querySelector('#clock main'); const clock = new HippieClock(container); clock.addCircle('base', .5, 1); - clock.addRing('seconds', .5, 1, 0, 60); + // clock.addRing('seconds', .5, 1, 0, 60); clock.draw(); setInterval(() => { clock.update(); }, 1000); + + document.getElementById('tglFormat').addEventListener('click', () => { + if (clock) { + clock.updateOptions({h24: !clock.options.h24}) + document.getElementById('tglFormat').textContent = clock.options.h24 ? '12-Stunden' : '24-Stunden'; + console.debug(clock); + } else { + console.log('No clock available'); + } + }); + {% endblock %} \ No newline at end of file From 05f2ab1c0daa9e90d8f89ab8c245e65b5e335f1d Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 10:49:51 +0100 Subject: [PATCH 05/19] feat: Update HippieClock - Add sections - Sections now use ring max value --- source/screens/demo/examples/clock.liquid | 78 +++++++++++++++++------ 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index a3690ff..84c1f63 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -295,7 +295,8 @@ tags: this.date = this.getTime(date); this.options = options || { size: Math.floor(this.getSize().value * 0.9), - h24: true + h24: true, + sections: true }; this.parts = this.createContext(['bkg', 'hands']); this.shapes = []; @@ -332,38 +333,68 @@ tags: part.context.clearRect(0, 0, part.element.width, part.element.height); }); - this.shapes.forEach(shape => { - if (shape.type === 'circle') { - const radius = this.toPixelSize(shape.radius) / 2; + let ctx = undefined; - this.parts[0].context.fillStyle = shape.color; - this.parts[0].context.beginPath(); - this.parts[0].context.arc( + this.shapes + .filter(item => item.type === 'circle') + .forEach((shape) => { + const radius = this.toPixelSize(shape.radius) / 2; + ctx = this.parts[0].context; + + ctx.fillStyle = shape.color; + ctx.beginPath(); + ctx.arc( this.toPixelX(shape.center), this.toPixelY(shape.center), radius, 0, Math.PI * 2 ); - this.parts[0].context.fill(); - } else if (shape.type === 'ring') { + ctx.fill(); + }); + + this.shapes + .filter(item => item.type === 'ring') + .forEach((shape) => { + if (this.options.sections) { + const outerRadius = this.toPixelSize(shape.radius) / 2; + const innerRadius = this.toPixelSize(shape.radius) / 2 - shape.stroke; + ctx = this.parts[0].context; + + for (let i = 0; i < shape.max; i++) { + const angle = (i * (360 / shape.max) - 90) * (Math.PI / 180); // -90 to start at top + const outerX = this.toPixelX(shape.center) + outerRadius * Math.cos(angle); + const outerY = this.toPixelY(shape.center) + outerRadius * Math.sin(angle); + const innerX = this.toPixelX(shape.center) + innerRadius * Math.cos(angle); + const innerY = this.toPixelY(shape.center) + innerRadius * Math.sin(angle); + + ctx.strokeStyle = 'black'; + // TODO: Stärke an shape.max orientieren + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(outerX, outerY); + ctx.lineTo(innerX, innerY); + ctx.stroke(); + } + } + const radius = this.toPixelSize(shape.radius) / 2 - shape.stroke / 2; const start = -0.5 * Math.PI; // Start at the top const angle = start + (2 * Math.PI * (shape.angle / shape.max)); + ctx = this.parts[1].context; - this.parts[1].context.strokeStyle = shape.color; - this.parts[1].context.lineWidth = shape.stroke; - this.parts[1].context.beginPath(); - this.parts[1].context.arc( + ctx.strokeStyle = shape.color; + ctx.lineWidth = shape.stroke; + ctx.beginPath(); + ctx.arc( this.toPixelX(shape.center), this.toPixelY(shape.center), radius, start, angle ); - this.parts[1].context.stroke(); - } - }); + ctx.stroke(); + }); } update() { @@ -484,27 +515,38 @@ tags: addRing(id, radius, angle, max, color = 'black', center = .5, stroke = 16) { this.shapes.push({type: 'ring', id, radius, angle, max, color, center, stroke}); } + + addSection(id, radius, color = 'black', center = .5, stroke = 1) { + this.shapes.push({type: 'section', id, radius, color, center, stroke}); + } } const container = document.querySelector('#clock main'); const clock = new HippieClock(container); + clock.addCircle('base', .5, 1); - // clock.addRing('seconds', .5, 1, 0, 60); clock.draw(); setInterval(() => { clock.update(); }, 1000); + // TODO: Aktionen gehören quasi zu HippieClock document.getElementById('tglFormat').addEventListener('click', () => { if (clock) { clock.updateOptions({h24: !clock.options.h24}) document.getElementById('tglFormat').textContent = clock.options.h24 ? '12-Stunden' : '24-Stunden'; - console.debug(clock); } else { console.log('No clock available'); } }); + document.getElementById('tglSections').addEventListener('click', () => { + if (clock) { + clock.updateOptions({sections: !clock.options.sections}) + } else { + console.log('No clock available'); + } + }); {% endblock %} \ No newline at end of file From 56633b364e314f404aed938b67c942952349b442 Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 10:50:43 +0100 Subject: [PATCH 06/19] feat: Remove legacy clock version --- source/screens/demo/examples/clock.liquid | 277 +--------------------- source/style/modules/_clock.scss | 15 -- 2 files changed, 3 insertions(+), 289 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 84c1f63..776c5d2 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -11,284 +11,13 @@ tags: -
-
- - -
-
+
{% endblock %} {% block script %} + + {% endcomment %} - - +{{ block.super -}} + -{% render 'hippie/partials/log-log' with 'Application ready... or is it?' as msg -%} {% endblock %} \ No newline at end of file diff --git a/source/templates/hippie/default.liquid b/source/templates/hippie/default.liquid index 4cb653e..b8cdbfd 100644 --- a/source/templates/hippie/default.liquid +++ b/source/templates/hippie/default.liquid @@ -29,7 +29,7 @@ {%- block body %}{% endblock -%} {%- block script %}{% endblock -%} diff --git a/source/templates/hippie/full.liquid b/source/templates/hippie/full.liquid index 5b22b17..d445469 100644 --- a/source/templates/hippie/full.liquid +++ b/source/templates/hippie/full.liquid @@ -37,9 +37,12 @@ {%- block body %}{% endblock -%} {% render 'hippie/partials/log-log' with 'BODY :: Loading script assets...' as msg -%} {%- block script %}{% endblock -%} +{% render 'hippie/partials/log-assets', state: true -%} +{% render 'hippie/partials/log-log', msg: 'BODY :: Assets loaded, running page specific script...', arg: true -%} {% render 'hippie/partials/log-log' with 'BODY end :: Page script might still be loading.' as msg -%} +{% render 'hippie/partials/log-log' with 'Application ready... or is it?' as msg -%} \ No newline at end of file diff --git a/source/templates/hippie/page.liquid b/source/templates/hippie/page.liquid index b6edd40..dd6e6ed 100644 --- a/source/templates/hippie/page.liquid +++ b/source/templates/hippie/page.liquid @@ -59,4 +59,4 @@ logPerf('EVENT :: jQuery \'ready\' event fired.'); }); -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/source/templates/hippie/simple.liquid b/source/templates/hippie/simple.liquid index b711fe6..b888886 100644 --- a/source/templates/hippie/simple.liquid +++ b/source/templates/hippie/simple.liquid @@ -7,9 +7,3 @@ {{ block.super -}} {% endblock %} - -{% block script %} - - - -{% endblock %} \ No newline at end of file From 7f4b4aeaee22e2108a64c32671c13ef660737d0c Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 18:47:01 +0100 Subject: [PATCH 14/19] feat: Changes to HippieClock - Make some methods private - Add wrap element to parts - Change color of sections - Fix resize by changing styles of wrap element --- source/screens/demo/examples/clock.liquid | 52 +++++++++++++---------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 4890c40..85c7ad9 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -30,7 +30,7 @@ tags: h24: true, sections: true }; - this.parts = this.createContext(['bkg', 'hands']); + this.parts = this.#createContext(['background', 'hands']); this.shapes = []; this.init(); @@ -56,8 +56,16 @@ tags: resize() { this.parts.forEach(part => { + this.updateOptions({size: Math.floor(this.getSize().value * 0.9)}) + + if (part.name === 'wrap') { + part.element.style.height = this.options.size + 'px'; + part.element.style.width = this.options.size + 'px'; + } + part.element.width = part.element.offsetWidth; part.element.height = part.element.offsetHeight; + this.draw(); }); } @@ -65,7 +73,7 @@ tags: draw() { // TODO: Nur geänderte Teile löschen this.parts.forEach(part => { - part.context.clearRect(0, 0, part.element.width, part.element.height); + part.context?.clearRect(0, 0, part.element.width, part.element.height); }); let ctx = undefined; @@ -73,14 +81,14 @@ tags: this.shapes .filter(item => item.type === 'circle') .forEach((shape) => { - const radius = this.toPixelSize(shape.radius) / 2; + const radius = this.#toPixelSize(shape.radius) / 2; ctx = this.parts[0].context; ctx.fillStyle = shape.color; ctx.beginPath(); ctx.arc( - this.toPixelX(shape.center), - this.toPixelY(shape.center), + this.#toPixelX(shape.center), + this.#toPixelY(shape.center), radius, 0, Math.PI * 2 @@ -92,18 +100,18 @@ tags: .filter(item => item.type === 'ring') .forEach((shape) => { if (this.options.sections) { - const outerRadius = this.toPixelSize(shape.radius) / 2; - const innerRadius = this.toPixelSize(shape.radius) / 2 - shape.stroke; + const outerRadius = this.#toPixelSize(shape.radius) / 2; + const innerRadius = this.#toPixelSize(shape.radius) / 2 - shape.stroke; ctx = this.parts[0].context; for (let i = 0; i < shape.max; i++) { const angle = (i * (360 / shape.max) - 90) * (Math.PI / 180); // -90 to start at top - const outerX = this.toPixelX(shape.center) + outerRadius * Math.cos(angle); - const outerY = this.toPixelY(shape.center) + outerRadius * Math.sin(angle); - const innerX = this.toPixelX(shape.center) + innerRadius * Math.cos(angle); - const innerY = this.toPixelY(shape.center) + innerRadius * Math.sin(angle); + const outerX = this.#toPixelX(shape.center) + outerRadius * Math.cos(angle); + const outerY = this.#toPixelY(shape.center) + outerRadius * Math.sin(angle); + const innerX = this.#toPixelX(shape.center) + innerRadius * Math.cos(angle); + const innerY = this.#toPixelY(shape.center) + innerRadius * Math.sin(angle); - ctx.strokeStyle = 'black'; + ctx.strokeStyle = `rgba(0, 0, 0, .25)`; ctx.lineWidth = mapRange(shape.max, 7, 72, .1, 5, true, true); ctx.beginPath(); ctx.moveTo(outerX, outerY); @@ -112,7 +120,7 @@ tags: } } - const radius = this.toPixelSize(shape.radius) / 2 - shape.stroke / 2; + const radius = this.#toPixelSize(shape.radius) / 2 - shape.stroke / 2; const start = -0.5 * Math.PI; // Start at the top const angle = start + (2 * Math.PI * (shape.angle / shape.max)); ctx = this.parts[1].context; @@ -121,8 +129,8 @@ tags: ctx.lineWidth = shape.stroke; ctx.beginPath(); ctx.arc( - this.toPixelX(shape.center), - this.toPixelY(shape.center), + this.#toPixelX(shape.center), + this.#toPixelY(shape.center), radius, start, angle @@ -149,15 +157,15 @@ tags: this.draw(); } - toPixelX(number) { + #toPixelX(number) { return number * this.parts[0].element.width; } - toPixelY(number) { + #toPixelY(number) { return number * this.parts[0].element.height; } - toPixelSize(number) { + #toPixelSize(number) { return number * Math.min(this.parts[0].element.width, this.parts[0].element.height); } @@ -278,7 +286,7 @@ tags: }; } - createContext(names) { + #createContext(names) { let parts = []; const wrap = document.createElement('div'); @@ -298,11 +306,11 @@ tags: canvas.width = canvas.offsetWidth; wrap.appendChild(canvas); - parts.push({name: name, element: canvas, context: canvas.getContext('2d')}); }); this.element.appendChild(wrap); + parts.push({name: 'wrap', element: wrap}); return parts; } @@ -347,7 +355,7 @@ tags: // TODO: Aktionen gehören quasi zu HippieClock document.getElementById('tglFormat').addEventListener('click', () => { if (clock) { - clock.updateOptions({h24: !clock.options.h24}) + clock.updateOptions({h24: !clock.options.h24}); document.getElementById('tglFormat').textContent = clock.options.h24 ? '12-Stunden' : '24-Stunden'; } else { console.log('No clock available'); @@ -356,7 +364,7 @@ tags: document.getElementById('tglSections').addEventListener('click', () => { if (clock) { - clock.updateOptions({sections: !clock.options.sections}) + clock.updateOptions({sections: !clock.options.sections}); } else { console.log('No clock available'); } From d0fde7cc6aab3467b70745210da98d9df486b32f Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 20:04:28 +0100 Subject: [PATCH 15/19] fix: HippieClock ring for hours --- source/screens/demo/examples/clock.liquid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 85c7ad9..2d7902e 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -39,7 +39,7 @@ tags: init() { this.addRing('seconds', 1, 21, 60, `rgb(250, 216, 3)`); this.addRing('minutes', .9, 46, 60, `rgb(242, 175, 19)`); - this.addRing('minutes', .8, 6, this.options.h24 ? 24 : 12, `rgb(211, 10, 81)`); + this.addRing('hours', .8, 6, this.options.h24 ? 24 : 12, `rgb(211, 10, 81)`); this.addRing('dotweek', .7, 2, 7, `rgb(142, 31, 104)`); this.addRing('dotmonth', .6, 12, this.getTime().daysMonth, `rgb(39, 63, 139)`); this.addRing('dotyear', .5, 256, this.getTime().daysYear, `rgb(60, 87, 154)`); From 91df239a42a9ec984e9f9e361952779ae7e6333d Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 20:05:50 +0100 Subject: [PATCH 16/19] feat: More private methods for HippieClock --- source/screens/demo/examples/clock.liquid | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 2d7902e..ba05a15 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -33,10 +33,10 @@ tags: this.parts = this.#createContext(['background', 'hands']); this.shapes = []; - this.init(); + this.#init(); } - init() { + #init() { this.addRing('seconds', 1, 21, 60, `rgb(250, 216, 3)`); this.addRing('minutes', .9, 46, 60, `rgb(242, 175, 19)`); this.addRing('hours', .8, 6, this.options.h24 ? 24 : 12, `rgb(211, 10, 81)`); @@ -47,14 +47,14 @@ tags: this.addRing('month', .3, 10, 12, `rgb(107, 199, 217)`); this.addRing('moon', .2, 4, 8, `rgb(82, 190, 209)`); - this.resize(); - window.addEventListener('resize', () => this.resize()); + this.#resize(); + window.addEventListener('resize', () => this.#resize()); console.debug(this); console.debug(this.getTime()); } - resize() { + #resize() { this.parts.forEach(part => { this.updateOptions({size: Math.floor(this.getSize().value * 0.9)}) From 6a574d92c270061bcfaed2ab674932678296a44c Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 20:57:15 +0100 Subject: [PATCH 17/19] feat: Add overlay to HippieClock - Add method to create overlay element - Use DateDisplay and TimeDisplay classes - Add button to toggle display - Update style for header - Add methods to handle shapes --- source/screens/demo/examples/clock.liquid | 98 +++++++++++++++++++++-- source/style/modules/_clock.scss | 6 ++ 2 files changed, 98 insertions(+), 6 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index ba05a15..4d581b9 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -8,8 +8,11 @@ tags: {% block body %}
- - + +
{% endblock %} @@ -20,7 +23,6 @@ tags: {% endblock %} \ No newline at end of file diff --git a/source/style/modules/_clock.scss b/source/style/modules/_clock.scss index b58fed5..0965587 100644 --- a/source/style/modules/_clock.scss +++ b/source/style/modules/_clock.scss @@ -1,6 +1,12 @@ @use "../hippie-style/hippie"; +@use "sass:map"; + .body_clock { + header { + z-index: map.get(hippie.$z-indexes, "content-top"); + } + main { display: flex; flex-flow: column nowrap; From a1aae6a90201f16e892f4d7c71b1ed0fc2424df2 Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 22:19:19 +0100 Subject: [PATCH 18/19] fix: Change size option on resize only once --- source/screens/demo/examples/clock.liquid | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 4d581b9..1b1e689 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -58,9 +58,8 @@ tags: } #resize() { + this.updateOptions({size: Math.floor(this.getSize().value * 0.9)}); this.parts.forEach(part => { - this.updateOptions({size: Math.floor(this.getSize().value * 0.9)}) - if (part.name === 'wrap') { part.element.style.height = this.options.size + 'px'; part.element.style.width = this.options.size + 'px'; From c3de29d63464335e1bb23e0fececdd6606e48b99 Mon Sep 17 00:00:00 2001 From: sthag Date: Sun, 1 Mar 2026 22:23:14 +0100 Subject: [PATCH 19/19] feat: Move element creation to #init() for HippieClock --- source/screens/demo/examples/clock.liquid | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/screens/demo/examples/clock.liquid b/source/screens/demo/examples/clock.liquid index 1b1e689..403926c 100644 --- a/source/screens/demo/examples/clock.liquid +++ b/source/screens/demo/examples/clock.liquid @@ -33,13 +33,16 @@ tags: sections: true, overlay: false }; - this.parts = this.#createContext(['background', 'hands']); + this.parts = []; this.shapes = []; this.#init(); } #init() { + this.#createContext(['background', 'hands']); + this.createOverlay(); + this.addRing('seconds', 1, 21, 60, `rgb(250, 216, 3)`); this.addRing('minutes', .9, 46, 60, `rgb(242, 175, 19)`); this.addRing('hours', .8, 6, this.options.h24 ? 24 : 12, `rgb(211, 10, 81)`); @@ -309,13 +312,11 @@ tags: canvas.width = canvas.offsetWidth; wrap.appendChild(canvas); - parts.push({name: name, element: canvas, context: canvas.getContext('2d')}); + this.parts.push({name: name, element: canvas, context: canvas.getContext('2d')}); }); this.element.appendChild(wrap); - parts.push({name: 'wrap', element: wrap}); - - return parts; + this.parts.push({name: 'wrap', element: wrap}); } createOverlay() { @@ -334,7 +335,8 @@ tags: left: '0px', height: '100%', width: '100%', - // display: this.options.overlay ? 'flex' : 'none', + display: this.options.overlay ? 'flex' : 'none', + // display: 'flex', justifyContent: 'center', alignItems: 'center', backgroundColor: `rgba(0, 0, 0, .6)`,