-
...now available on my personal App Loader (look for "ColorWheel") and - hopefully - soon on the official one as well.
-
...and here is the same in a touchable version:
//----------------------------------------------------------------------------// //-- ColorWheel - draws a "wheel" of good looking colors --// //----------------------------------------------------------------------------// let ColorList = [ '#0000FF', '#8000FF', '#FF00FF', '#FF0080', '#FF0000', '#FF8000', '#FFFF00', '#80FF00', '#00FF00', '#00FF80', '#00FFFF', '#0080FF' ]; let ScreenWidth = g.getWidth(), CenterX = ScreenWidth/2; let ScreenHeight = g.getHeight(), CenterY = ScreenHeight/2; let outerRadius = Math.min(CenterX,CenterY) * 0.9; let innerRadius = outerRadius*0.5; let sin = Math.sin, cos = Math.cos; let twoPi = 2*Math.PI, halfPi = Math.PI/2; let DeltaPhi = twoPi/72; let Epsilon = 0.001; g.clear(); g.setColor(0,0,0); g.fillRect(0,0, ScreenWidth,ScreenHeight); for (let i = 0; i < 12; i++) { let Phi0 = i * twoPi/12, Phi1 = (i+1) * twoPi/12; let Polygon = []; for (let Phi = Phi0; Phi <= Phi1+Epsilon; Phi += DeltaPhi) { Polygon.push(CenterX + outerRadius * sin(Phi)); Polygon.push(CenterY - outerRadius * cos(Phi)); } for (let Phi = Phi1; Phi >= Phi0-Epsilon; Phi -= DeltaPhi) { Polygon.push(CenterX + innerRadius * sin(Phi)); Polygon.push(CenterY - innerRadius * cos(Phi)); } g.setColor(ColorList[i]); g.fillPoly(Polygon); } g.setColor(1,1,1); g.fillCircle(CenterX,CenterY, innerRadius); g.setFont12x20(); g.setFontAlign(0,0); g.setColor(0,0,0); g.drawString('Tap', CenterX,CenterY-20); g.drawString('on', CenterX,CenterY); g.drawString('Color', CenterX,CenterY+20); Bangle.on('touch', function (Button,Position) { Bangle.buzz(); let dx = Position.x - CenterX; let dy = Position.y - CenterY; let Radius = Math.sqrt(dx*dx + dy*dy); let Color; switch (true) { case (Radius > outerRadius): Color = '#000000'; break; case (Radius < innerRadius): Color = '#FFFFFF'; break; default: let Phi = Math.atan2(dy,dx) + halfPi; if (Phi < 0) { Phi += twoPi; } if (Phi > twoPi) { Phi -= twoPi; } let Index = Math.floor(12*Phi/twoPi); Color = ColorList[Index]; } g.setColor(1,1,1); g.fillCircle(CenterX,CenterY, innerRadius); g.setColor(0,0,0); g.drawString(Color, CenterX,CenterY); });
-
...now available on my personal App Loader (look for "ColorWheel") and - hopefully - soon on the official one as well.
-
...and here is the same in a touchable version:
let ColorList = [ '#0000FF', '#8000FF', '#FF00FF', '#FF0080', '#FF0000', '#FF8000', '#FFFF00', '#80FF00', '#00FF00', '#00FF80', '#00FFFF', '#0080FF' ]; let ScreenWidth = g.getWidth(), CenterX = ScreenWidth/2; let ScreenHeight = g.getHeight(), CenterY = ScreenHeight/2; let outerRadius = Math.min(CenterX,CenterY) * 0.9; let innerRadius = outerRadius*0.5; let sin = Math.sin, cos = Math.cos; let twoPi = 2*Math.PI, halfPi = Math.PI/2; let DeltaPhi = twoPi/72; let Epsilon = 0.001; g.clear(); g.setColor(0,0,0); g.fillRect(0,0, ScreenWidth,ScreenHeight); for (let i = 0; i < 12; i++) { let Phi0 = i * twoPi/12, Phi1 = (i+1) * twoPi/12; let Polygon = []; for (let Phi = Phi0; Phi <= Phi1+Epsilon; Phi += DeltaPhi) { Polygon.push(CenterX + outerRadius * sin(Phi)); Polygon.push(CenterY - outerRadius * cos(Phi)); } for (let Phi = Phi1; Phi >= Phi0-Epsilon; Phi -= DeltaPhi) { Polygon.push(CenterX + innerRadius * sin(Phi)); Polygon.push(CenterY - innerRadius * cos(Phi)); } g.setColor(ColorList[i]); g.fillPoly(Polygon); } g.setColor(1,1,1); g.fillCircle(CenterX,CenterY, innerRadius); g.setFont12x20(); g.setFontAlign(0,0); g.setColor(0,0,0); g.drawString('Tap', CenterX,CenterY-20); g.drawString('on', CenterX,CenterY); g.drawString('Color', CenterX,CenterY+20); Bangle.on('touch', function (Button,Position) { let dx = Position.x - CenterX; let dy = Position.y - CenterY; let Radius = Math.sqrt(dx*dx + dy*dy); let Color; switch (true) { case (Radius > outerRadius): Color = '#000000'; break; case (Radius < innerRadius): Color = '#FFFFFF'; break; default: let Phi = Math.atan2(dy,dx) + halfPi; if (Phi < 0) { Phi += twoPi; } if (Phi > twoPi) { Phi -= twoPi; } let Index = Math.floor(12*Phi/twoPi); Color = ColorList[Index]; } g.setColor(1,1,1); g.fillCircle(CenterX,CenterY, innerRadius); g.setColor(0,0,0); g.drawString(Color, CenterX,CenterY); });
-
In the last few days, the thread Graphics Color questions has been hijacked for several small example programs related to several..."graphics color questions".
In order to simplify finding more specific solutions, I've started a new thread for the following example, namely:
a small color wheel using colors with "full" (0 and 1) and "half" (0.5) values
let ColorList = [ '#0000FF', '#8000FF', '#FF00FF', '#FF0080', '#FF0000', '#FF8000', '#FFFF00', '#80FF00', '#00FF00', '#00FF80', '#00FFFF', '#0080FF' ]; let ScreenWidth = g.getWidth(), CenterX = ScreenWidth/2; let ScreenHeight = g.getHeight(), CenterY = ScreenHeight/2; let outerRadius = Math.min(CenterX,CenterY) * 0.9; let innerRadius = outerRadius*0.5; let sin = Math.sin, cos = Math.cos; let twoPi = 2*Math.PI; let DeltaPhi = twoPi/72; let Epsilon = 0.001; g.clear(); g.setColor(0,0,0); g.fillRect(0,0, ScreenWidth,ScreenHeight); for (let i = 0; i < 12; i++) { let Phi0 = i * twoPi/12, Phi1 = (i+1) * twoPi/12; let Polygon = []; for (let Phi = Phi0; Phi <= Phi1+Epsilon; Phi += DeltaPhi) { Polygon.push(CenterX + outerRadius * sin(Phi)); Polygon.push(CenterY - outerRadius * cos(Phi)); } for (let Phi = Phi1; Phi >= Phi0-Epsilon; Phi -= DeltaPhi) { Polygon.push(CenterX + innerRadius * sin(Phi)); Polygon.push(CenterY - innerRadius * cos(Phi)); } g.setColor(ColorList[i]); g.fillPoly(Polygon); }
Hopefully it will help you finding proper good-looking colors
-
Well,
try this one for the moment:
let ScreenWidth = g.getWidth(), PatchWidth = ScreenWidth/6; let ScreenHeight = g.getHeight(), PatchHeight = ScreenHeight/6; g.clear(); for (let i = 0; i < 27; i++) { let x = (i % 6) * PatchWidth; let y = Math.floor(i/6) * PatchHeight; let R = i % 3; let G = Math.floor(i/3) % 3; let B = Math.floor(i/9); g.setColor(R/2,G/2,B/2); g.fillRect(x,y, x+PatchWidth-1,y+PatchHeight-1); } g.setFont12x20(); Bangle.on('touch', function (Button,Position) { let x = Math.floor(Position.x / PatchWidth); let y = Math.floor(Position.y / PatchHeight); let i = y*6 + x; if (i >= 27) { return; } let R = i % 3; let G = Math.floor(i/3) % 3; let B = Math.floor(i/9); let HexValues = ['00','80','FF']; g.setColor(1,1,1); g.fillRect(3*PatchWidth,4*PatchHeight, ScreenWidth,ScreenHeight); g.setColor(0,0,0); g.drawString( '#' + HexValues[R] + HexValues[G] + HexValues[B], 3*PatchWidth,4*PatchHeight+6 ); });
I'll make a "real" application out of it as soon as I find the time (it's Christmas right now, you know...time for the family)
-
And just for the records: here is the same experiment for "quarter colors", i.e. RGB channel values 0, 0.25, 0.5, 0.75 and 1.0:
let ScreenWidth = g.getWidth(), PatchWidth = ScreenWidth/12; let ScreenHeight = g.getHeight(), PatchHeight = ScreenHeight/12; g.clear(); for (let i = 0; i < 125; i++) { let x = (i % 12) * PatchWidth; let y = Math.floor(i/12) * PatchHeight; let R = i % 5; let G = Math.floor(i/5) % 5; let B = Math.floor(i/25); g.setColor(R/4,G/4,B/4); g.fillRect(x,y, x+PatchWidth-1,y+PatchHeight-1); }
It seems that channel values 0/0.5/1.0 still look acceptable while quarter values do not...
-
Based on the idea with "half colors", I wrote the following little test
let ScreenWidth = g.getWidth(), PatchWidth = ScreenWidth/6; let ScreenHeight = g.getHeight(), PatchHeight = ScreenHeight/6; g.clear(); for (let i = 0; i < 27; i++) { let x = (i % 6) * PatchWidth; let y = Math.floor(i/6) * PatchHeight; let R = i % 3; let G = Math.floor(i/3) % 3; let B = Math.floor(i/9); g.setColor(R/2,G/2,B/2); g.fillRect(x,y, x+PatchWidth-1,y+PatchHeight-1); }
The result does not look too bad (if you can live with half of the original spatial resolution)
-
-
Perfect, thank you very much for your response (particularly the "TODO" comments in there)!
This gives me the information I need to
- draw my own background prior to any widgets and
- then to draw all widgets on top of that
Thanks a lot!
Edit:
- I followed your suggestion and implemented a modified version of "Bangle.drawWidgets" - it works like a charm!
- what surprises me, though, is the call of
g.setClipRectRect
in line 27 - is this part of the original code or did you edit it?
Edit 2:
- I found it: you edited the original code! Thus, you may perhaps want to correct that line
Thanks again for your effort!
- draw my own background prior to any widgets and
-
-
Hello,
I'm currently developing a watch face with a background image that covers the whole screen.
But since I still want to support widgets, I have to draw them somehow after filling the display with my background image.
However, the well-known sequence
Bangle.loadWidgets(); Bangle.drawWidgets();
fills the widget area with white and, thus, destroys my background image.
How can I draw widgets without clearing their area?
-
-
-
I just found this thread because I had problems with the few supported colors myself...
For those interested: here is a short program displaying the supported colors
let ScreenWidth = g.getWidth(); let BarStart = ScreenWidth/2, BarEnd = ScreenWidth-5; let BarHeight = 20; g.clear(); let ColorNames = 'black blue green cyan red magenta yellow white'.split(' '); let ColorValues = '#000000 [#0000FF](http://forum.espruino.com/search/?q=%230000FF) [#00FF00](http://forum.espruino.com/search/?q=%2300FF00) [#00FFFF](http://forum.espruino.com/search/?q=%2300FFFF) [#FF0000](http://forum.espruino.com/search/?q=%23FF0000) [#FF00FF](http://forum.espruino.com/search/?q=%23FF00FF) [#FFFF00](http://forum.espruino.com/search/?q=%23FFFF00) [#FFFFFF](http://forum.espruino.com/search/?q=%23FFFFFF)'.split(' '); g.setFont12x20(); for (let i = 0; i < 8; i++) { let y = 20*i+5; g.setColor('#000000'); g.drawString(ColorNames[i], 5,y); g.setColor(ColorValues[i]); g.fillRect(BarStart,y, BarEnd,y+BarHeight); }
Edit: oops - the final Markdown renderer seems to completely misunderstand my color codes (and try to render them as links) - the "Preview" is still working!
@Gordon you should have a look into the forum's code or ask the maintainers to fix that bug
-
I guess I can answer this question myself: simply retry updating - after a while it will (hopefully) proceed.
Nevertheless, these problems are quite annoying...
Nota bene: it may be helpful to reload the App Loader page (at https://banglejs.com/apps/) in order to reset its internal BLE state - I found that the Bangle sometimes leaves the browser in a state that does not allow to reconnect the watch...
-
Yesterday, I got my two new Bangles ("for both hands"!) - and, right after connecting the first one to my desktop, I just wanted to update the applications that came with the watch (from within https://banglejs.com/apps/).
However, update failed with the browser messages
Launcher Update failed Reference Error: appListStr is not defined Bootloader Update failed Reference Error: appListStr is not defined Update failed, no Apps can be updated
(unfortunately, these messages disappear soon after being shown so that I cannot simply copy-and-paste them here). The watch itself, it wants me to
Hold the button to reload
- but even then, I can not reconnect the watch until I reboot it.Does anybody have an idea how to proceed?
Thanks in advance for any help!
-
-
This is probably the strangest "project" I ever made...
Since none of the five 360° servos in a set bought on eBay worked, and the dealer's "assistance" was limited to repeatedly telling me the required pulse widths, I built a setup using an "Original Espruino" as servo controller and recorded a "proof video" to show:
- voltage, current and pulse widths are correct (this shows a competitor's product)
- in fact, not a single one of the servos supplied worked!
The video is available on Vimeo
Thanks to Espruino, experimenting with the servos and testing them was just trivial - and all the rest took less than an hour to build, record and upload!
FYI: the code I had to write for the proof video was just
analogWrite(C7, 0.10, {freq:100});
- voltage, current and pulse widths are correct (this shows a competitor's product)
-
Hello Gordon,
thank you very much for your response - and don't worry about the delay (as a backer I'm following your activities and problems myself and know how busy your days are).
But it's good to know how simple it may be to use and refer to Espruino-specific diagrams and images!
Thank you and good success with Bangle 2!
-
I changed your code a bit, and now everything works as foreseen. Here is my complete test
//var Servo = require('servo').connect(C7, { range:2 }); function Servo_connect (pin,options) { var interval, currentPos; var offs = 1, mul = 1; if (options && options.range) { mul = options.range; offs = 1.5-(mul/2); } return {move:function(pos, time, callback) { if (typeof time === 'function') { callback = time; time = undefined; } if (typeof time !== 'number') time = 1000; var amt = 0; if (currentPos===undefined) currentPos = pos; if (interval) clearInterval(interval); var initial = currentPos; interval = setInterval(function() { currentPos = pos*amt + initial*(1-amt); digitalPulse(pin, 1, offs+E.clip(currentPos,0,1)*mul); if (amt >= 1) { clearInterval(interval); interval = undefined; if (callback) callback(); return; } else { amt += 1000.0 / (20*time); } }, 20); }}; } let Servo = Servo_connect(C7, { range:2 }); let Count = 0; function move () { if (Count < 10) { Count++; print('Count: ' + Count); Servo.move(1, 1000, move); } } move();
Since you
clearInterval
, an explicitreturn
is not necessary, but it may be a good idea to restricttime
to values > 0 in order to avoid a division by zero (or negative values) -
I just looked into the code you referenced - and I found a potential problem:
if (callback) callback();
Shouldn't you always
return callback()
?Amendment: I found the mistake - if a callback is given,
time
must be specified as well, otherwise the callback function is taken as thetime
argument.If you like, you may change the beginning of your
move
function like so:return {move:function(pos, time, callback) { if (typeof time === 'function') { callback = time; time = undefined; } if (typeof time !== 'number') time = 1000;
At least, you should protect the
time
argument better (an error message would be fine, but you may not have enough resources on the device for such an approach) -
indeed, that's all my code - I just wanted to "quickly" test a servo (but nothing works quickly if I am touching it - I tend to break everything)
Amendment: I also just checked the firmware state (just to be sure): and, yes, it is 2v10
Amendment 2: just to be sure, I flashed 2v10 one more time and tried my code again - with the same result.
-
I just tried to drive an SG90 Micro Servo with 360° gear from an Original Espruino, wired to pin C7 (as the example suggests) -
{ range:2 }
was the outcome of another test with an "ordinary" SG90.var Servo = require('servo').connect(C7, { range:2 }); let Count = 0; function move () { if (Count < 10) { Count++; Servo.move(1, move); } } move();
However, when uploading this code from the Web IDE it leads to an endless loop of error messages (and finally crashes the Chrome browser):
Uncaught Error: Pulse Time given for digitalPulse is less than 0, or not a number at line 1 col 87 ...Pulse(l,1,g+E.clip(b,0,1)*e);c+=1E3/(20*f) ^ in function called from system ...
Does this code try to recursively call
Servo.move
rather than my functionmove
? But why does it then lead to an endless loop?Amendment: renaming my function
move
tomoveServo
still loops endlessly
The whole area is tappable: