diff --git a/TODO.md b/TODO.md index 6af7f1b..5c33350 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,9 @@ - Keep placeholder and demo stuff - Move other things - Prevent styles to be global +- Adapt bootstrap utility API + - https://github.com/twbs/bootstrap/blob/main/scss/utilities/_api.scss + - https://github.com/twbs/bootstrap/blob/main/scss/_utilities.scss # JS diff --git a/source/code/game.js b/source/code/game.js new file mode 100644 index 0000000..b961fdb --- /dev/null +++ b/source/code/game.js @@ -0,0 +1,313 @@ +class HippieCrosshair { + constructor(canvas, options = {}) { + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + + this.debug = options.debug || false; + + const defaults = { + crosshair: { + size: 16, + thickness: 2, + color: '#000', + gapSize: 8, + style: 'cross' + }, + connector: { + distance: 128, // Distance to draw next symbol + spacing: 64, // Space between symbols + size: 8, + color: '#000', + style: 'arrow', + visibility: true + }, + line: { + color: 'rgba(0, 0, 0, 0.1)', + width: 1 + } + }; + const merged = this.mergeOptions(defaults, options); + const { crosshair, connector, line } = merged; + + // Crosshair options + this.size = crosshair.size; + this.thickness = crosshair.thickness; + this.color = crosshair.color; + this.gapSize = crosshair.gapSize; + this.style = crosshair.style; + + // Connector options + this.distance = connector.distance; + this.spacing = connector.spacing; + this.connectorSize = connector.size; + this.connectorColor = connector.color; + this.connectorStyle = connector.style; + this.connectorShow = connector.visibility; + + // Line options + this.lineColor = line.color || '#fff'; + this.lineWidth = line.width || 1; + + this.mouseX = canvas.width / 2; + this.mouseY = canvas.height / 2; + + // Animation control + this.isAnimating = true; + this.animationFrameId = null; + + this.setupEventListeners(); + this.animate(); + } + + mergeOptions(defaults, options) { + const merged = JSON.parse(JSON.stringify(defaults)); + + if (options.crosshair) { + Object.assign(merged.crosshair, options.crosshair); + } + if (options.connector) { + Object.assign(merged.connector, options.connector); + } + if (options.line) { + Object.assign(merged.line, options.line); + } + + return merged; + } + + setupEventListeners() { + document.addEventListener('mousemove', (event) => { + this.mouseX = event.clientX; + this.mouseY = event.clientY; + }); + } + + animate() { + if (!this.isAnimating) { + this.animationFrameId = requestAnimationFrame(() => this.animate()); + return; + } + + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + + if (this.connectorShow) { + if (this.debug) this.drawLine(); + this.drawConnector(); + } + + // TODO: Autom. Zug zum Zentrum hin ermöglichen + this.drawCrosshair(); + + this.animationFrameId = requestAnimationFrame(() => this.animate()); + } + + drawLine() { + const centerX = this.canvas.width / 2; + const centerY = this.canvas.height / 2; + + this.ctx.strokeStyle = this.lineColor; + this.ctx.lineWidth = this.lineWidth; + this.ctx.beginPath(); + this.ctx.moveTo(centerX, centerY); + this.ctx.lineTo(this.mouseX, this.mouseY); + this.ctx.stroke(); + } + + // TODO: Ausblenden nach Distanz + drawConnector() { + const centerX = this.canvas.width / 2; + const centerY = this.canvas.height / 2; + + const dx = this.mouseX - centerX; + const dy = this.mouseY - centerY; + const delta = Math.sqrt(dx * dx + dy * dy); + + // Only draw connectors if cursor is far enough from center + if (delta < this.distance) { + return; + } + + const angle = Math.atan2(dy, dx); + const count = Math.floor((delta - this.distance) / this.spacing); + + for (let i = 0; i < count; i++) { + const distance = this.distance + (i * this.spacing); + const x = centerX + Math.cos(angle) * distance; + const y = centerY + Math.sin(angle) * distance; + + this.drawSymbol(x, y, angle); + } + } + + drawSymbol(x, y, angle = 0) { + this.ctx.fillStyle = this.connectorColor; + this.ctx.strokeStyle = this.connectorColor; + this.ctx.lineWidth = 1; + + switch (this.connectorStyle) { + case 'circle': + this.ctx.beginPath(); + this.ctx.arc(x, y, this.connectorSize / 2, 0, Math.PI * 2); + this.ctx.fill(); + break; + case 'diamond': + const size = this.connectorSize - (this.connectorSize / 4); + this.ctx.beginPath(); + this.ctx.moveTo(x, y - size); + this.ctx.lineTo(x + size, y); + this.ctx.lineTo(x, y + size); + this.ctx.lineTo(x - size, y); + this.ctx.closePath(); + this.ctx.fill(); + break; + case 'square': + this.ctx.fillRect( + x - this.connectorSize / 2, + y - this.connectorSize / 2, + this.connectorSize, + this.connectorSize + ); + break; + case 'arrow': + this.arrow(x, y, angle); + break; + } + } + + arrow(x, y, angle) { + const size = this.connectorSize - (this.connectorSize / 4); + + this.ctx.save(); + this.ctx.translate(x, y); + this.ctx.rotate(angle); + + // Arrow pointing right + this.ctx.beginPath(); + this.ctx.moveTo(size, 0); // Tip + this.ctx.lineTo(-size, -size); // Back left + // this.ctx.lineTo(-size * 0.4, 0); // Middle + this.ctx.lineTo(-size, size); // Back right + this.ctx.closePath(); + this.ctx.fill(); + + this.ctx.restore(); + } + + drawCrosshair() { + this.ctx.strokeStyle = this.color; + this.ctx.lineWidth = this.thickness; + this.ctx.lineCap = 'round'; + + switch (this.style) { + case 'cross': + this.cross(); + break; + case 'circle': + this.circle(); + break; + case 'dot': + this.dot(); + break; + case 'level': + this.level(); + break; + } + } + + cross() { + // Horizontal line + this.ctx.beginPath(); + this.ctx.moveTo(this.mouseX - this.size, this.mouseY); + this.ctx.lineTo(this.mouseX - this.gapSize, this.mouseY); + this.ctx.stroke(); + + this.ctx.beginPath(); + this.ctx.moveTo(this.mouseX + this.gapSize, this.mouseY); + this.ctx.lineTo(this.mouseX + this.size, this.mouseY); + this.ctx.stroke(); + + // Vertical line + this.ctx.beginPath(); + this.ctx.moveTo(this.mouseX, this.mouseY - this.size); + this.ctx.lineTo(this.mouseX, this.mouseY - this.gapSize); + this.ctx.stroke(); + + this.ctx.beginPath(); + this.ctx.moveTo(this.mouseX, this.mouseY + this.gapSize); + this.ctx.lineTo(this.mouseX, this.mouseY + this.size); + this.ctx.stroke(); + } + + circle() { + // Outer circle + this.ctx.beginPath(); + this.ctx.arc(this.mouseX, this.mouseY, this.size, 0, Math.PI * 2); + this.ctx.stroke(); + + // Inner dot + this.ctx.fillStyle = this.color; + this.ctx.beginPath(); + this.ctx.arc(this.mouseX, this.mouseY, this.thickness, 0, Math.PI * 2); + this.ctx.fill(); + } + + dot() { + this.ctx.fillStyle = this.color; + this.ctx.beginPath(); + this.ctx.arc(this.mouseX, this.mouseY, this.size / 4, 0, Math.PI * 2); + this.ctx.fill(); + } + + level() { + this.ctx.beginPath(); + this.ctx.moveTo(this.mouseX - this.size * 2, this.mouseY); + this.ctx.lineTo(this.mouseX - this.gapSize * 2, this.mouseY); + this.ctx.stroke(); + + this.ctx.beginPath(); + this.ctx.arc(this.mouseX, this.mouseY, this.size, 0, Math.PI); + this.ctx.stroke(); + + this.ctx.beginPath(); + this.ctx.moveTo(this.mouseX + this.gapSize * 2, this.mouseY); + this.ctx.lineTo(this.mouseX + this.size * 2, this.mouseY); + this.ctx.stroke(); + + this.ctx.fillStyle = this.color; + this.ctx.beginPath(); + this.ctx.arc(this.mouseX, this.mouseY, this.thickness, 0, Math.PI * 2); + this.ctx.fill(); + } + + setCrosshairStyle(style) { + this.style = style; + } + + setCrosshairColor(color) { + this.color = color; + } + + setConnectorStyle(style) { + this.connectorStyle = style; + } + + setConnectorColor(color) { + this.connectorColor = color; + } + + setConnectorVisibility(visible) { + this.connectorShow = visible; + } + + startAnimation() { + this.isAnimating = true; + } + + stopAnimation() { + this.isAnimating = false; + } + + toggleAnimation() { + this.isAnimating = !this.isAnimating; + } +} diff --git a/source/code/hippie/app.js b/source/code/hippie/app.js index 7cda8b6..eb6eda9 100644 --- a/source/code/hippie/app.js +++ b/source/code/hippie/app.js @@ -540,6 +540,15 @@ function mapRange(value, inMin, inMax, outMin, outMax, reverse = false, clamp = return mapped; } +function zeroFill(number, width) { + width -= number.toString().length; + + if (width > 0) { + return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number; + } + return number + ''; // always return a string +} + // Source - https://stackoverflow.com/a/47480429 // Posted by Etienne Martin, modified by community. See post 'Timeline' for change history // Retrieved 2026-03-08, License - CC BY-SA 4.0 @@ -603,91 +612,6 @@ Clock.prototype.formatDigits = function (val) { return val; }; -function ongoing() { - - var now = new Date(); - - var w = Math.floor(now.getDay()); - var D = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag']; - var DNumb = Math.floor(now.getDate()); - var MNumb = Math.floor(now.getMonth()); - var M = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'MaiOktober', 'November', 'Dezember']; - var y = Math.floor(now.getYear()); - if (y < 999) y += 1900; - - var ms = Math.floor(now.getMilliseconds()); - var s = Math.floor(now.getSeconds()); - var m = Math.floor(now.getMinutes() + s / 60); - var h = Math.floor(now.getHours() + m / 60); - - var j2000 = new Date(); // Bezugspunkt ist der 1.1.2000 0:00 UT (entspricht JD 2451544,5) - j2000.setUTCFullYear(2000, 0, 1); - j2000.setUTCHours(0, 0, 0, 0); - - var utc = new Date(); - utc.setUTCFullYear(y, MNumb, DNumb); // Monate müssen im Wertebereich 0...11 übergeben werden - utc.setUTCHours(h, m, s, ms); - - var utc0 = new Date(); - utc0.setUTCFullYear(y, MNumb, DNumb); - utc0.setUTCHours(0, 0, 0, 0); - - var jd = 2451544.5 + (utc - j2000) / 86400000; // Zählung erfolgt in Millisekunden, 1 Tag = 86.400.000 ms - var jdUTC0 = 2451544.5 + (utc0 - j2000) / 86400000; - - var N = jd - 2451545.0; - var L = 280.460 + 0.9856474 * N; // mittlere ekliptikale Länge der Sonne - var g = 357.528 + 0.9856003 * N; // mittlere Anomalie - var el = L + 1.915 * Math.sin(g) + 0.020 * Math.sin(2 * g); - var e = 23.439 - 0.0000004 * N; - var rektaszension = Math.atan((Math.cos(e) * Math.sin(el)) / Math.cos(el)); - - var T = (jdUTC0 - 2451545.0) / 36525; - var stGMT = (((6 * 3600) + (41 * 60) + 50.54841) + (8640184.812866 * T) + (0.093104 * Math.pow(T, 2)) - (0.0000062 * Math.pow(T, 3))) / 3600; - - var stGMT2 = 6.697376 + 2400.05134 * T + 1.002738 * T; - var hWGMT = stGMT2 * 15; - var hW = hWGMT + 11.9566185772; - - var st = (stGMT + (now.getUTCHours() * 1.00273790935)) + (11.9566185772 / 15); // Sommerzeit muss noch berücksichtigt werden - var st24 = Math.abs(st - (Math.round(st / 24) * 24)); - var stH = Math.floor(st24); - var stM = Math.floor((st24 % 1) * 60); - var stS = zeroFill(Math.floor((((st24 % 1) * 60) % 1) * 60), 2); - - var travelWidth = document.body.clientWidth; - var travelHeight = document.body.clientHeight; - var sunPosX = 0; - var sunPosY = 0; - var moonPosX = 0; - var moonPosY = 0; - - var sun = $('#sun').css({ - 'left': (s / 60) * travelWidth, - 'top': (m / 60) * travelHeight - }); - - $('#day').text(D[w]); - $('#dayNumb').text(DNumb); - $('#month').text(M[MNumb]); - $('#year').text(y); - $('#time').text('' + zeroFill(h, 2) + ':' + zeroFill(m, 2) + ':' + zeroFill(s, 2)); - - $('#julian').text(jd.toFixed(6)); - //$('#star').text(stH + ':' + stM + ':' + stS); - $('#star').text(stH + ':' + stM); - $('#star1').text(stGMT); - $('#star2').text(stGMT2); -} - -function zeroFill(number, width) { - width -= number.toString().length; - if (width > 0) { - return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number; - } - return number + ''; // always return a string -} - //Länge der Balken im Diagram berechnen function barwidth(size, G, W) { var s = size; diff --git a/source/data/start.json b/source/data/start.json index cc0da22..65bfb14 100644 --- a/source/data/start.json +++ b/source/data/start.json @@ -8,7 +8,7 @@ "href": "/demo/basics.html" }, { - "text": "Drag", - "href": "/demo/examples/ui/drag.html" + "text": "Portal", + "href": "/demo/examples/portal.html" } ] \ No newline at end of file diff --git a/source/screens/demo/basics.liquid b/source/screens/demo/basics.liquid index d3c7a08..f1c8560 100644 --- a/source/screens/demo/basics.liquid +++ b/source/screens/demo/basics.liquid @@ -801,7 +801,7 @@ order: 2 <fieldset> realisiert.

-
+
Einfache Eingabeelemente -
+
@@ -846,7 +846,7 @@ order: 2
Einfache Eingabeelemente mit Stil -
+
@@ -883,7 +883,7 @@ order: 2 Information oder lockern das Erscheinungsbild auf.

Hier nun eine Liste weiterer Arten von Eingabefeldern:

-
+
diff --git a/source/screens/demo/components.liquid b/source/screens/demo/components.liquid index 2ea1d8d..98f582c 100644 --- a/source/screens/demo/components.liquid +++ b/source/screens/demo/components.liquid @@ -286,12 +286,17 @@ order: 3 Zelle mit Angabe der Breite. -
table.flexible>tr>td+td.truncate.ellipsis+td
- +
table.grid>(tr>td+td.ellipsis+td)*2
+
- - + + + + + + +
IndexZelle mit viel Inhalt der nicht umbricht und eingeschränkt wird.Zelle mit Angabe der Breite.Zelle mit viel Inhalt der nicht umbricht und eingeschränkt wird.Inhalt bestimmt die Breite
101Zelle mit viel Inhalt der nicht umbricht und eingeschränkt wird.Zelle
diff --git a/source/screens/demo/examples/10print.liquid b/source/screens/demo/examples/10print.liquid index 9ee9246..8ed878e 100644 --- a/source/screens/demo/examples/10print.liquid +++ b/source/screens/demo/examples/10print.liquid @@ -5,8 +5,7 @@ tags: --- {% layout 'hippie/simple.liquid' %} -{% block head %} -{{ block.super -}} +{% block style %}