From 28927f7849dbb9fa4a05ceba18a38dd6b445c242 Mon Sep 17 00:00:00 2001 From: pinq- Date: Sat, 1 Apr 2023 07:34:32 +0300 Subject: [PATCH] New futures - Hole can be circle or square - Hole can be with number or without - Draw circle takes whole object in as a variable --- apps/rings/app.js | 79 ++++++++++-- apps/rings/battery.js | 284 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 351 insertions(+), 12 deletions(-) create mode 100644 apps/rings/battery.js diff --git a/apps/rings/app.js b/apps/rings/app.js index 0fb768ea8..318ccb9ec 100644 --- a/apps/rings/app.js +++ b/apps/rings/app.js @@ -10,9 +10,9 @@ const watch = { x:0, y:0, w:0, h:0, color:"#000000", - dateRing : { size:109, weight:20, color:"#00FF00", cursor:14, numbers: true }, - hourRing : { size:85, weight:20, color:"#00FFFF", cursor:14, numbers: true }, - minuteRing : { size:61, weight:20, color:"#FFFF00", cursor:14, numbers: true }, + dateRing : { size:109, weight:20, color:"#00FF00", numbers: true, range: 30 , bubble:false}, + hourRing : { size:82, weight:20, color:"#00FFFF", numbers: true, range: 12, bubble:true}, + minuteRing : { size:55, weight:18, color:"#FFFF00", numbers: false, range: 60, bubble:false}, screen : { width:g.getWidth(), height:g.getHeight(), centerX: g.getWidth() *0.5, centerY: g.getHeight() * 0.5, cursor: 14, font:"6x8:2" }, }; @@ -72,6 +72,52 @@ function drawTimeCircle(color, size, weight, range, value ) { } + +function drawCircle(ringValues, offset, value ) { + // variables for vertex transformations and positioning time + let tver, tobj, tran; + let ttime = (value / ringValues.range) * (Math.PI * 2); + + // draw circle + g.setColor(ringValues.color).fillCircle(watch.screen.centerX, watch.screen.centerY, ringValues.size + offset); + g.setColor("#000000").fillCircle(watch.screen.centerX, watch.screen.centerY, ringValues.size - ringValues.weight + offset); + // draw line + //let location_x = watch.screen.centerX +(ringValues.size + offset) * Math.cos((-(value / ringValues.range)+0.25)*2*Math.PI); + //let location_y = watch.screen.centerY -(ringValues.size + offset) * Math.sin((-(value / ringValues.range)+0.25)*2*Math.PI); + tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate:ttime }; + if(ringValues.bubble){ + tver = [-1, 0, 1, 0, 1, -ringValues.size-offset, -1, -(ringValues.size + offset -21)]; + tran = g.transformVertices(tver, tobj); + if(ringValues.numbers){ + g.setColor("#000000").fillCircle((tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2, 17 + offset/10); + }else{ + g.setColor("#000000").fillCircle((tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2, 10 + offset/10); + } + }else{ + if(ringValues.numbers){ + tver = [-watch.screen.cursor, 0, watch.screen.cursor, 0, watch.screen.cursor, -ringValues.size*1.01 - offset, -watch.screen.cursor, -ringValues.size*1.05 - offset]; + }else{ + tver = [-watch.screen.cursor * 0.4, 0, watch.screen.cursor * 0.4, 0, watch.screen.cursor *0.4, -ringValues.size*1.01 - offset, -watch.screen.cursor*0.4, -ringValues.size*1.05 - offset]; + } + tran = g.transformVertices(tver, tobj); + g.fillPoly(tran); + + } + + // Draw numbers + if(ringValues.numbers){ + // size - 21 is the right offset to get the numbers aligned in the circle. + tver = [-1, 0, 1, 0, 1, -ringValues.size-offset, -1, -(ringValues.size + offset -21)]; + tran = g.transformVertices(tver, tobj); + //g.setColor(1,1,1); + g.setFontAlign(0,0).setFont(watch.screen.font, 2).setColor(1,1,1); + g.drawString(value, (tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2 ); + + } + + +} + // Draws text for month and year in date circle function drawMonthCircleText( text, circleSize, range, value){ @@ -87,7 +133,7 @@ function drawMonthCircleText( text, circleSize, range, value){ var gr = Graphics.createArrayBuffer(24,16,1,{msb:true}); var grimg = gr.asImage(); grimg.transparent = 1; - monthCircleTextBuffer.setColor(0,0,0); + monthCircleTextBuffer.setColor(1,1,1); for(z=0; z < text.length; z++){ tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate: ((z + 1) / range) * (Math.PI * 2) }; @@ -142,14 +188,17 @@ function shrinkCircles(toggle){ // Draw the date ring (unless it's the last run of an expansion). if(counter < 11 || toggle){ - drawTimeCircle(watch.dateRing.color, watch.dateRing.size + delta, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() ); + + //drawTimeCircle(watch.dateRing.color, watch.dateRing.size + delta, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() ); + drawCircle(watch.dateRing, delta, date.getDate()); // Draw month and year in date ring drawMonthCircleText( month[date.getMonth()]+" "+date.getFullYear(), watch.dateRing.size - 24, getDays(date.getFullYear(), date.getMonth()+1), date.getDate()) ; } - drawTimeCircle(watch.hourRing.color, watch.hourRing.size + delta, watch.hourRing.weight, 12, date.getHours() ); - - drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size + delta, watch.minuteRing.weight, 60, date.getMinutes() ); + //drawTimeCircle(watch.hourRing.color, watch.hourRing.size + delta, watch.hourRing.weight, 12, date.getHours() ); + drawCircle(watch.hourRing, delta, date.getHours()); + drawCircle(watch.minuteRing, delta, date.getMinutes()); + //drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size + delta, watch.minuteRing.weight, 60, date.getMinutes() ); counter += 1; setTimeout(shrinkCircles, 10, toggle); @@ -172,13 +221,19 @@ function draw() { // If unlocked, draw date ring and text and make hour and minute rings smaller if(!Bangle.isLocked()){ unLockedOffset = 24; - drawTimeCircle(watch.dateRing.color, watch.dateRing.size - unLockedOffset, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() ); + console.log("jee"); + var days_month = getDays(date.getFullYear(), date.getMonth()+1); + // if the day has changed + if(watch.dateRing.range != days_month) watch.dateRing.range = days_month; + //drawTimeCircle(watch.dateRing.color, watch.dateRing.size - unLockedOffset, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() ); + drawCircle(watch.dateRing, -unLockedOffset, days_month); drawMonthCircleText( month[date.getMonth()]+" "+date.getFullYear(), watch.dateRing.size - unLockedOffset, getDays(date.getFullYear(), date.getMonth()+1), date.getDate()) ; } - drawTimeCircle(watch.hourRing.color, watch.hourRing.size - unLockedOffset, watch.hourRing.weight, 12, date.getHours() ); - drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size -unLockedOffset , watch.minuteRing.weight, 60, date.getMinutes() ); - + //drawTimeCircle(watch.hourRing.color, watch.hourRing.size - unLockedOffset, watch.hourRing.weight, 12, date.getHours() ); + //drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size -unLockedOffset , watch.minuteRing.weight, 60, date.getMinutes() ); + drawCircle(watch.hourRing, -unLockedOffset, date.getHours()); + drawCircle(watch.minuteRing, -unLockedOffset, date.getMinutes()); queueDraw(); } diff --git a/apps/rings/battery.js b/apps/rings/battery.js new file mode 100644 index 000000000..c628199ec --- /dev/null +++ b/apps/rings/battery.js @@ -0,0 +1,284 @@ +// Rings watch face +// for Bangle.js 2 +// by Amos Blanton +// Remixed from / inspired by Rinkulainen watch face by Jukio Kallio + +// To Do: +// Make Month / year text buffer 1/2 size +// Optimize text positioning transforms + +const watch = { + x:0, y:0, w:0, h:0, + color:"#000000", + dateRing : { size:109, weight:20, color:"#00FF00", numbers: true, range: 30 , bubble:true}, + hourRing : { size:82, weight:20, color:"#00FFFF", numbers: true, range: 12, bubble:true}, + minuteRing : { size:55, weight:18, color:"#FFFF00", numbers: true, range: 60, bubble:false}, + batteryRing: { size :30, weight:10, color:"#ff3300", numbers: false, range: 100, bubble:false}, + screen : { width:g.getWidth(), height:g.getHeight(), centerX: g.getWidth() *0.5, centerY: g.getHeight() * 0.5, cursor: 14, font:"6x8:2" }, +}; + +const month= ["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY", + "AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"]; + +var wait = 60000; // wait time, normally a minute +// timeout used to update every minute +var drawTimeout; +// Global for use in shrink / unshrink animations +var counter = 1; + +// Buffer for month circle text, 1/2 screen size (will be scaled up) +var monthCircleTextBuffer= Graphics.createArrayBuffer(watch.screen.width,watch.screen.height,1,{msb:true}); +var monthCircleTextImg = monthCircleTextBuffer.asImage(); +monthCircleTextImg.transparent = 1; +var lastMonthCircleImageText = ""; + +// Calculate number of days in this month / year for date ring +const getDays = (year, thisMonth) => { + return new Date(year, thisMonth, 0).getDate(); // getMonth() Jan = 0. +}; + +// Schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, wait - (Date.now() % wait)); +} + +// Draws a time circle (date, hours, minutes) +function drawTimeCircle(color, size, weight, range, value ) { + // variables for vertex transformations and positioning time + var tver, tobj, tran; + var ttime = (value / range) * (Math.PI * 2); + + // draw circle and line + g.setColor(color).fillCircle(watch.screen.centerX, watch.screen.centerY, size); + g.setColor("#000000").fillCircle(watch.screen.centerX, watch.screen.centerY, size - weight); + + tver = [-watch.screen.cursor, 0, watch.screen.cursor, 0, watch.screen.cursor, -size*1.01, -watch.screen.cursor, -size*1.05]; + + tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate:ttime }; + tran = g.transformVertices(tver, tobj); + g.fillPoly(tran); + + // Draw numbers + g.setFontAlign(0,0).setFont(watch.screen.font, 2).setColor(1,1,1); + + // size - 21 is the right offset to get the numbers aligned in the circle. + tver = [-1, 0, 1, 0, 1, -size, -1, -(size -21)]; + tran = g.transformVertices(tver, tobj); + g.setColor(1,1,1); + g.drawString(value, (tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2 ); + +} + +function drawArc(percent, color, ArchR) { + let offset = 0; + let end = 360; + let radius = ArchR + 2; + + if (percent <= 0) return; // no gauge needed + if (percent > 1) percent = 1; + + let startRotation = -offset; + let endRotation = startRotation - (end * percent); + + g.setColor(color); + // convert to radians + startRotation *= Math.PI / 180; + let amt = Math.PI / 10; + endRotation = (endRotation * Math.PI / 180) - amt; + // all we need to draw is an arc, because we'll fill the center + let poly = [watch.screen.centerX, watch.screen.centerY]; + for (let r = startRotation; r > endRotation; r -= amt) + poly.push( + watch.screen.centerX - radius * Math.sin(r), + watch.screen.centerY - radius * Math.cos(r) + ); + g.fillPoly(poly); + g.setColor("#000000").fillCircle(watch.screen.centerX, watch.screen.centerY, ArchR - 10); + g.setColor(color).fillCircle(watch.screen.centerX - (radius -5) * Math.sin(endRotation + amt), watch.screen.centerY - (radius -5) * Math.cos(endRotation + amt), 4); +} + + +function drawCircle(ringValues, offset, value ) { + // variables for vertex transformations and positioning time + let tver, tobj, tran; + let ttime = (value / ringValues.range) * (Math.PI * 2); + + // draw circle + g.setColor(ringValues.color).fillCircle(watch.screen.centerX, watch.screen.centerY, ringValues.size + offset); + g.setColor("#000000").fillCircle(watch.screen.centerX, watch.screen.centerY, ringValues.size - ringValues.weight + offset); + // draw line + //let location_x = watch.screen.centerX +(ringValues.size + offset) * Math.cos((-(value / ringValues.range)+0.25)*2*Math.PI); + //let location_y = watch.screen.centerY -(ringValues.size + offset) * Math.sin((-(value / ringValues.range)+0.25)*2*Math.PI); + tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate:ttime }; + if(ringValues.bubble){ + tver = [-1, 0, 1, 0, 1, -ringValues.size-offset, -1, -(ringValues.size + offset -21)]; + tran = g.transformVertices(tver, tobj); + g.setColor("#000000").fillCircle((tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2, 17 + offset/10); + }else{ + tver = [-watch.screen.cursor, 0, watch.screen.cursor, 0, watch.screen.cursor, -ringValues.size*1.01 - offset, -watch.screen.cursor, -ringValues.size*1.05 - offset]; + tran = g.transformVertices(tver, tobj); + g.fillPoly(tran); + + } + + // Draw numbers + if(ringValues.numbers){ + // size - 21 is the right offset to get the numbers aligned in the circle. + tver = [-1, 0, 1, 0, 1, -ringValues.size-offset, -1, -(ringValues.size + offset -21)]; + tran = g.transformVertices(tver, tobj); + //g.setColor(1,1,1); + g.setFontAlign(0,0).setFont(watch.screen.font, 2).setColor(1,1,1); + g.drawString(value, (tran[4]+tran[6]) / 2 , (tran[5]+tran[7]) / 2 ); + + } + + +} + +// Draws text for month and year in date circle +function drawMonthCircleText( text, circleSize, range, value, delta){ + + // If the text isn't the same as last time, write it into a graphic object. + if(text != lastMonthCircleImageText){ + + monthCircleTextBuffer.clear(); + monthCircleTextBuffer.fillRect(0,0,watch.screen.width,watch.screen.height); + + var tver, tobj, tran; + + // From here: https://forum.espruino.com/comments/16781795/ + var gr = Graphics.createArrayBuffer(24,16,1,{msb:true}); + var grimg = gr.asImage(); + grimg.transparent = 1; + monthCircleTextBuffer.setColor(1,1,1); + + for(z=0; z < text.length; z++){ + tobj = { x:watch.screen.centerX, y:watch.screen.centerY, scale:1, rotate: ((z + 1) / range) * (Math.PI * 2) }; + tver = [-1, 0, 1, 0, 1, -circleSize, -1, -(circleSize -21)]; + tran = monthCircleTextBuffer.transformVertices(tver, tobj); + gr.clear().setColor(1,1,1).fillRect(0,0,24,16).setColor(0,0,0).setFont(watch.screen.font).setFontAlign(0,0).drawString(text[z],12,8); + + monthCircleTextBuffer.drawImage(grimg, + (tran[4]+tran[6]) / 2, + (tran[5]+tran[7]) / 2, + {rotate:((z+1) / range) * (Math.PI * 2) }); + } + + lastMonthCircleImageText = text; + } + + // Determine correct rotation for text in ring ( opposite the date position ) + var offset = value + (range / 2) - (text.length / 2); + if(offset > range) + offset = offset - range; + var rotation = (offset / range) * (Math.PI * 2); + + // Draw the image of text to the screen at that rotation + g.drawImage(monthCircleTextImg, watch.screen.centerX, watch.screen.centerY, {scale:1, rotate:rotation }); + +} + +// Animate by shrinking or expanding circles +function shrinkCircles(toggle){ + // If there's a queued draw operation,removeit so animation isn't interrupted. + if (drawTimeout) clearTimeout(drawTimeout); + var date = new Date(); + var delta = 1; + + if(counter > 12) + { + counter = 1; + // We're finished, so queue next draw. + queueDraw(); + return; + } + + if(toggle) // We are shrinking + delta = counter * 2 * -1; + else // We are expanding + delta = counter *2 - 24; + + // Clear space on screen. + g.setColor(watch.color); + g.fillRect(0, 0, watch.screen.width, watch.screen.height); + + // Draw the date ring (unless it's the last run of an expansion). + if(counter < 11 || toggle){ + drawTimeCircle(watch.dateRing.color, watch.dateRing.size + delta, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() ); + //drawCircle(watch.dateRing, delta, date.getDate()); + // Draw month and year in date ring + drawMonthCircleText( month[date.getMonth()]+" "+date.getFullYear(), watch.dateRing.size - 24, getDays(date.getFullYear(), date.getMonth()+1), date.getDate()) ; + } + + drawCircle(watch.hourRing, delta, date.getHours()); + drawCircle(watch.minuteRing, delta, date.getMinutes()); + + + counter += 1; + setTimeout(shrinkCircles, 10, toggle); +} + + +// main draw function +function draw() { + // make date object + var date = new Date(); + var unLockedOffset = 0; + + // Reset the state of the graphics library + g.reset(); + + // Clear the area where we want to draw the time + g.setColor(watch.color); + g.fillRect(0, 0, watch.screen.width, watch.screen.height); + + // If unlocked, draw date ring and text and make hour and minute rings smaller + if(!Bangle.isLocked()){ + unLockedOffset = 24; + var days_month = getDays(date.getFullYear(), date.getMonth()+1); + // if the day has changed + if(watch.dateRing.range != days_month) watch.dateRing.range = days_month; + //drawTimeCircle(watch.dateRing.color, watch.dateRing.size - unLockedOffset, watch.dateRing.weight, getDays(date.getFullYear(), date.getMonth()+1), date.getDate() ); + drawCircle(watch.dateRing, -unLockedOffset, days_month); + drawMonthCircleText( month[date.getMonth()]+" "+date.getFullYear(), watch.dateRing.size - unLockedOffset, getDays(date.getFullYear(), date.getMonth()+1), date.getDate()) ; + } + + //drawTimeCircle(watch.hourRing.color, watch.hourRing.size - unLockedOffset, watch.hourRing.weight, 12, date.getHours() ); + //drawTimeCircle(watch.minuteRing.color, watch.minuteRing.size -unLockedOffset , watch.minuteRing.weight, 60, date.getMinutes() ); + drawCircle(watch.hourRing, -unLockedOffset, date.getHours()); + drawCircle(watch.minuteRing, -unLockedOffset, date.getMinutes()); + drawArc(1, watch.batteryRing.color, watch.batteryRing.size); + //drawCircle(watch.batteryRing, -unLockedOffset, E.getBattery()); + queueDraw(); +} + +// Trigger shrink / expand animation on unlock / lock events +Bangle.on('lock', on=>{ + if (on) { // locked, expand circles + counter = 1; + shrinkCircles(false); + } else + { // unlocked, shrink circles and show date ring + counter = 1; + shrinkCircles(true); + } +}); + + +// End function definitions / start of initial execution. + +// Clear the screen once, at startup +g.clear(); + +// draw immediately at first +draw(); + + +// console.log("Whatevs"); + +// Show launcher when middle button pressed +Bangle.setUI("clock"); \ No newline at end of file