|
@ -0,0 +1,478 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="svg4149"
|
||||
viewBox="0 0 19.191 30.044001"
|
||||
height="30.044001"
|
||||
width="19.191">
|
||||
<defs
|
||||
id="defs4151">
|
||||
<linearGradient
|
||||
id="linearGradient28799-4">
|
||||
<stop
|
||||
id="stop28801-13"
|
||||
offset="0"
|
||||
style="stop-color:#fefefc;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#fefefc;stop-opacity:1"
|
||||
offset="0.75733864"
|
||||
id="stop28807-8" />
|
||||
<stop
|
||||
id="stop28803-8"
|
||||
offset="1"
|
||||
style="stop-color:#d4d4d4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="14.572236"
|
||||
fy="137.66095"
|
||||
fx="223.19559"
|
||||
cy="137.66095"
|
||||
cx="223.19559"
|
||||
gradientTransform="matrix(1.0857794,-0.03431182,0.03943781,1.2479887,-154.54194,-26.542647)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient29032"
|
||||
xlink:href="#linearGradient28799-4" />
|
||||
<radialGradient
|
||||
r="14.572236"
|
||||
fy="137.66095"
|
||||
fx="223.19559"
|
||||
cy="137.66095"
|
||||
cx="223.19559"
|
||||
gradientTransform="matrix(0.81524244,-0.03431182,0.02961133,1.2479887,-129.43743,-26.542647)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient29648"
|
||||
xlink:href="#linearGradient28799-4" />
|
||||
<linearGradient
|
||||
id="linearGradient14392-7">
|
||||
<stop
|
||||
style="stop-color:#3e2a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop14394-8" />
|
||||
<stop
|
||||
style="stop-color:#ad780a;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop14396-6" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient14392-7"
|
||||
id="linearGradient14477"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.87491199,0,0,0.81148755,60.367186,62.586953)"
|
||||
x1="442.03912"
|
||||
y1="371.54401"
|
||||
x2="490.12241"
|
||||
y2="293.58548" />
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient14392-7"
|
||||
id="linearGradient14485"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(4e-6,9.6185359e-6)"
|
||||
x1="442.03912"
|
||||
y1="371.54401"
|
||||
x2="490.12241"
|
||||
y2="293.58548" />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14186-9">
|
||||
<path
|
||||
id="path14188-1"
|
||||
d="m 137.57703,281.0191 c 1.59929,-0.66295 3.3982,-0.78361 5.10074,-0.46963 1.70253,0.31398 3.31141,1.04948 4.74342,2.02239 2.86402,1.94583 4.98821,4.77774 7.02263,7.57952 4.67189,6.43406 9.16868,13.00227 13.24488,19.8293 3.30635,5.53766 6.34352,11.25685 10.16415,16.45304 2.49398,3.3919 5.3066,6.53947 7.813,9.92221 2.50639,3.38273 4.72794,7.05586 5.83931,11.11662 1.44411,5.27653 0.88463,11.09291 -1.62666,15.95302 -1.76663,3.41896 -4.47646,6.35228 -7.77242,8.33898 -3.29595,1.9867 -7.17064,3.01444 -11.01635,2.87021 -6.11413,-0.2293 -11.69944,-3.28515 -17.38362,-5.54906 -11.58097,-4.6125 -24.15978,-6.0594 -36.09666,-9.65174 -3.66859,-1.10404 -7.27582,-2.4107 -10.96988,-3.42629 -1.64125,-0.45122 -3.30866,-0.8482 -4.85875,-1.55144 -1.55008,-0.70325 -2.999548,-1.7491 -3.86171,-3.21675 -0.666391,-1.13439 -0.948386,-2.47002 -0.930187,-3.78554 0.0182,-1.31552 0.325889,-2.61453 0.773815,-3.85158 0.895851,-2.47409 2.343262,-4.71374 3.320162,-7.15696 1.59511,-3.98935 1.88169,-8.38839 1.66657,-12.67942 -0.21511,-4.29103 -0.91078,-8.54478 -1.20454,-12.83115 -0.13118,-1.91406 -0.18066,-3.85256 0.18479,-5.73598 0.36545,-1.88343 1.17577,-3.72459 2.55771,-5.05541 1.27406,-1.22693 2.96492,-1.95531 4.69643,-2.31651 1.73151,-0.3612 3.51533,-0.37747 5.28367,-0.33762 1.76833,0.0399 3.54067,0.13425 5.30351,-0.0106 1.76284,-0.14488 3.53347,-0.54055 5.06911,-1.41828 1.45996,-0.83447 2.65433,-2.0745 3.64374,-3.43424 0.9894,-1.35974 1.78909,-2.84573 2.60891,-4.31396 0.81983,-1.46823 1.66834,-2.93151 2.74157,-4.22611 1.07324,-1.2946 2.38923,-2.42304 3.94266,-3.06698"
|
||||
style="fill:#402c07;fill-opacity:1;stroke:none" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath15031-3">
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 248.06066,184.61218 c -2.60091,3.4397 -5.23338,6.85555 -7.89695,10.24696 -2.83301,3.60715 -5.70116,7.1866 -8.58729,10.75139 -3.54135,4.37407 -7.15155,8.79286 -9.44912,13.93045 -1.97407,4.41422 -2.91014,9.20748 -4.26498,13.84932 -1.53862,5.27153 -3.62627,10.37023 -5.97071,15.33612 -2.1648,4.58539 -4.54978,9.06293 -6.93891,13.53553 -1.73823,3.25407 -3.50515,6.58104 -4.10782,10.22071 -0.47627,2.87632 -0.19849,5.84423 0.53376,8.66626 0.73224,2.82202 1.90964,5.5106 3.23775,8.10601 5.66724,11.07504 14.17003,20.62168 24.24176,27.92472 4.57063,3.31418 9.46669,6.18109 14.60245,8.52595 2.78247,1.27041 5.71355,2.40436 8.77186,2.45744 1.52915,0.0265 3.0741,-0.22544 4.47434,-0.84055 1.40024,-0.6151 2.65068,-1.60373 3.48254,-2.88709 1.02278,-1.5779 1.36992,-3.53829 1.16461,-5.40743 -0.2053,-1.86914 -0.93484,-3.65294 -1.91324,-5.25873 -2.38997,-3.92251 -6.1652,-6.76055 -9.79642,-9.57343 -7.84055,-6.07358 -15.42466,-12.48038 -22.68212,-19.23996 -2.04911,-1.90854 -4.0984,-3.87759 -5.53019,-6.28412 -1.3943,-2.34352 -2.14763,-5.01375 -2.65783,-7.69253 -1.39963,-7.34872 -1.0404,-15.0827 1.45958,-22.13343 0.97802,-2.75834 2.27066,-5.39225 3.51815,-8.03965 2.1622,-4.58855 4.21133,-9.26299 7.04933,-13.46723 3.53268,-5.23334 8.24484,-9.67275 11.15147,-15.27803 2.45457,-4.7335 3.49353,-10.05742 4.36185,-15.31831 0.66531,-4.03089 1.24751,-8.07549 1.74613,-12.13037"
|
||||
id="path15033-2" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14822-9">
|
||||
<path
|
||||
d="m 386.1875,285.32775 c -0.40516,-1.10369 -1.11845,-2.08156 -1.9907,-2.86987 -0.87226,-0.78832 -1.90049,-1.39229 -2.98278,-1.85155 -2.16459,-0.91852 -4.52053,-1.26149 -6.83152,-1.69556 -2.17919,-0.40931 -4.34179,-0.90631 -6.52782,-1.27734 -2.27136,-0.38551 -4.6179,-0.63213 -6.8653,-0.1253 -1.96583,0.44333 -3.7845,1.45879 -5.27172,2.81864 -1.48723,1.35984 -2.64911,3.0564 -3.48499,4.89007 -1.47218,3.22952 -1.93451,6.86503 -1.65394,10.40316 0.20882,2.63325 0.87532,5.34594 2.60877,7.33912 1.40065,1.61052 3.38733,2.61526 5.43398,3.22092 3.52502,1.04316 7.36663,0.98822 10.86038,-0.1553 5.76689,-1.93113 10.87568,-5.77387 14.33034,-10.77903 1.13861,-1.64963 2.11217,-3.44809 2.5532,-5.4034 0.33597,-1.48955 0.34831,-3.08112 -0.1779,-4.51456"
|
||||
id="path14824-1"
|
||||
style="fill:none;stroke:#ce5c00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14822-2-4">
|
||||
<path
|
||||
d="m 386.1875,285.32775 c -0.40516,-1.10369 -1.11845,-2.08156 -1.9907,-2.86987 -0.87226,-0.78832 -1.90049,-1.39229 -2.98278,-1.85155 -2.16459,-0.91852 -4.52053,-1.26149 -6.83152,-1.69556 -2.17919,-0.40931 -4.34179,-0.90631 -6.52782,-1.27734 -2.27136,-0.38551 -4.6179,-0.63213 -6.8653,-0.1253 -1.96583,0.44333 -3.7845,1.45879 -5.27172,2.81864 -1.48723,1.35984 -2.64911,3.0564 -3.48499,4.89007 -1.47218,3.22952 -1.93451,6.86503 -1.65394,10.40316 0.20882,2.63325 0.87532,5.34594 2.60877,7.33912 1.40065,1.61052 3.38733,2.61526 5.43398,3.22092 3.52502,1.04316 7.36663,0.98822 10.86038,-0.1553 5.76689,-1.93113 10.87568,-5.77387 14.33034,-10.77903 1.13861,-1.64963 2.11217,-3.44809 2.5532,-5.4034 0.33597,-1.48955 0.34831,-3.08112 -0.1779,-4.51456"
|
||||
id="path14824-6-5"
|
||||
style="fill:none;stroke:#ce5c00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="linearGradient14518-6">
|
||||
<stop
|
||||
id="stop14540-0"
|
||||
offset="0"
|
||||
style="stop-color:#110800;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#a65a00;stop-opacity:0.80000001;"
|
||||
offset="0.59066743"
|
||||
id="stop14542-5" />
|
||||
<stop
|
||||
style="stop-color:#ff921e;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop14522-4" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14489-3">
|
||||
<path
|
||||
style="fill:url(#linearGradient14485);fill-opacity:1;stroke:none"
|
||||
d="m 516.00562,331.8756 c -0.6714,1.71905 -1.62682,3.32679 -2.81579,4.73826 -2.6238,3.11482 -6.268,5.17039 -9.89648,7.01985 -6.1886,3.15437 -12.60169,5.92177 -18.41964,9.71654 -3.89802,2.54249 -7.4959,5.52671 -10.86016,8.74238 -2.87719,2.75012 -5.60582,5.68745 -8.83247,8.01771 -3.25567,2.35122 -7.01915,4.05426 -10.99061,4.6502 -4.83026,0.72481 -9.82134,-0.21289 -14.29898,-2.16416 -3.13754,-1.36728 -6.15569,-3.3229 -7.96301,-6.22931 -1.81425,-2.91754 -2.22807,-6.48813 -2.23266,-9.92375 -0.008,-6.07666 1.11824,-12.09004 2.17848,-18.07349 0.88097,-4.97177 1.71949,-9.95483 2.26013,-14.97502 0.98337,-9.13118 0.9763,-18.35278 0.3199,-27.51327 -0.10993,-1.53416 -0.23754,-3.0832 -0.008,-4.60412 0.22922,-1.52092 0.85475,-3.0367 2.02069,-4.03986 1.07696,-0.9266 2.52093,-1.33598 3.93947,-1.4145 1.41854,-0.0785 2.83404,0.14655 4.23982,0.35197 3.31254,0.48405 6.65159,0.8649 9.88917,1.71656 2.04284,0.53738 4.03315,1.25925 6.0722,1.81081 3.40258,0.92039 6.96639,1.36144 10.46739,0.95192 3.76917,-0.44089 7.42987,-1.85678 11.22363,-1.76474 1.55658,0.0378 3.1015,0.33171 4.58649,0.79985 1.51539,0.47772 3.00914,1.16182 4.12281,2.29512 0.84639,0.8613 1.43579,1.94539 1.87872,3.06879 0.65982,1.67352 1.01492,3.457 1.16703,5.24945 0.13475,1.58788 0.11343,3.19441 0.41433,4.75933 0.49503,2.57458 1.84746,4.92305 3.52848,6.93494 1.68102,2.01189 3.68982,3.72048 5.69641,5.40783 1.99908,1.68103 4.0106,3.35469 6.16708,4.82839 1.0121,0.69165 2.05642,1.33949 3.01736,2.10062 0.96094,0.76113 1.84466,1.6468 2.44543,2.71535 0.81492,1.44944 1.06377,3.2077 0.68307,4.82635 h 2e-5"
|
||||
id="path14491-6" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14481-1">
|
||||
<path
|
||||
style="fill:url(#linearGradient14485);fill-opacity:1;stroke:none"
|
||||
d="m 516.00562,331.8756 c -0.6714,1.71905 -1.62682,3.32679 -2.81579,4.73826 -2.6238,3.11482 -6.268,5.17039 -9.89648,7.01985 -6.1886,3.15437 -12.60169,5.92177 -18.41964,9.71654 -3.89802,2.54249 -7.4959,5.52671 -10.86016,8.74238 -2.87719,2.75012 -5.60582,5.68745 -8.83247,8.01771 -3.25567,2.35122 -7.01915,4.05426 -10.99061,4.6502 -4.83026,0.72481 -9.82134,-0.21289 -14.29898,-2.16416 -3.13754,-1.36728 -6.15569,-3.3229 -7.96301,-6.22931 -1.81425,-2.91754 -2.22807,-6.48813 -2.23266,-9.92375 -0.008,-6.07666 1.11824,-12.09004 2.17848,-18.07349 0.88097,-4.97177 1.71949,-9.95483 2.26013,-14.97502 0.98337,-9.13118 0.9763,-18.35278 0.3199,-27.51327 -0.10993,-1.53416 -0.23754,-3.0832 -0.008,-4.60412 0.22922,-1.52092 0.85475,-3.0367 2.02069,-4.03986 1.07696,-0.9266 2.52093,-1.33598 3.93947,-1.4145 1.41854,-0.0785 2.83404,0.14655 4.23982,0.35197 3.31254,0.48405 6.65159,0.8649 9.88917,1.71656 2.04284,0.53738 4.03315,1.25925 6.0722,1.81081 3.40258,0.92039 6.96639,1.36144 10.46739,0.95192 3.76917,-0.44089 7.42987,-1.85678 11.22363,-1.76474 1.55658,0.0378 3.1015,0.33171 4.58649,0.79985 1.51539,0.47772 3.00914,1.16182 4.12281,2.29512 0.84639,0.8613 1.43579,1.94539 1.87872,3.06879 0.65982,1.67352 1.01492,3.457 1.16703,5.24945 0.13475,1.58788 0.11343,3.19441 0.41433,4.75933 0.49503,2.57458 1.84746,4.92305 3.52848,6.93494 1.68102,2.01189 3.68982,3.72048 5.69641,5.40783 1.99908,1.68103 4.0106,3.35469 6.16708,4.82839 1.0121,0.69165 2.05642,1.33949 3.01736,2.10062 0.96094,0.76113 1.84466,1.6468 2.44543,2.71535 0.81492,1.44944 1.06377,3.2077 0.68307,4.82635 h 2e-5"
|
||||
id="path14483-3" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14473-5">
|
||||
<path
|
||||
style="fill:url(#linearGradient14477);fill-opacity:1;stroke:none"
|
||||
d="m 511.82669,331.89986 c -0.60617,1.40358 -1.44178,2.70776 -2.46357,3.84504 -2.32524,2.58805 -5.50706,4.22246 -8.65855,5.69652 -5.42045,2.53534 -11.00071,4.7788 -16.11556,7.88485 -3.38301,2.05437 -6.53696,4.47221 -9.50169,7.09434 -2.52461,2.23286 -4.92977,4.6271 -7.72763,6.50627 -2.88313,1.93644 -6.17534,3.29888 -9.61582,3.77358 -4.21817,0.58201 -8.55335,-0.18335 -12.51035,-1.75619 -2.7091,-1.07682 -5.36625,-2.6185 -6.96693,-5.05501 -1.53813,-2.3413 -1.9333,-5.25173 -1.95338,-8.053 -0.0354,-4.93859 0.96501,-9.81816 1.90598,-14.66641 0.78215,-4.02995 1.52682,-8.0717 1.97741,-12.15204 0.81784,-7.40607 0.66114,-14.88536 0.27989,-22.32668 -0.064,-1.24906 -0.13361,-2.5105 0.0789,-3.74301 0.21256,-1.23251 0.73646,-2.45247 1.68171,-3.27147 0.93914,-0.8137 2.20952,-1.15942 3.45104,-1.2115 1.24152,-0.0521 2.47642,0.16381 3.70512,0.34927 2.88969,0.43617 5.81087,0.7091 8.65215,1.39297 1.78651,0.43 3.53091,1.02011 5.31265,1.46945 2.98632,0.75312 6.09645,1.10709 9.15804,0.77247 3.2941,-0.36004 6.50688,-1.50957 9.81969,-1.43207 1.35838,0.0318 2.70755,0.27142 4.01277,0.64907 1.31265,0.3798 2.61744,0.9202 3.6071,1.86246 0.72535,0.69061 1.25006,1.56936 1.64371,2.49029 0.57625,1.34814 0.88626,2.79994 1.02105,4.25986 0.11897,1.28855 0.10468,2.59405 0.36251,3.86214 0.4369,2.14878 1.63966,4.08139 3.11506,5.70353 1.4754,1.62214 3.22406,2.96752 4.9559,4.31247 1.75634,1.36398 3.50975,2.7398 5.39565,3.91818 0.88228,0.55128 1.79349,1.05932 2.63473,1.67142 0.84123,0.61209 1.61878,1.33907 2.14473,2.23668 0.68386,1.16711 0.90229,2.59857 0.59763,3.91652 h 2e-5"
|
||||
id="path14475-9" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath14656-7">
|
||||
<path
|
||||
d="m 304.84727,225.44951 c 6.01627,4.92338 9.77707,12.317 10.94319,20.00305 1.8254,12.03148 -2.34636,24.07488 -6.44591,35.53273 -0.81749,2.28481 -1.63978,4.59033 -1.96473,6.99513 -0.32495,2.4048 -0.11897,4.94825 1.02948,7.08594 1.30279,2.42497 3.73227,4.12469 6.36677,4.92292 2.58877,0.78438 5.39365,0.76103 8.01466,0.0922 2.62101,-0.66882 5.06097,-1.96774 7.18716,-3.63996 5.48002,-4.30997 8.75799,-10.98552 10.01043,-17.84394 1.25243,-6.85841 0.63908,-13.92879 -0.551,-20.7983 -1.62313,-9.36916 -4.30898,-18.53961 -7.74003,-27.40773 -2.51766,-6.50732 -5.46794,-12.91081 -9.61753,-18.52016 -4.04611,-5.46946 -9.16208,-10.08954 -13.10336,-15.63502 -2.73209,-3.84412 -4.89983,-8.13097 -8.1917,-11.50812 -1.64594,-1.68858 -3.57654,-3.13527 -5.76975,-4.00143 -2.19321,-0.86616 -4.66356,-1.12446 -6.93254,-0.48249 -1.50468,0.42573 -2.89193,1.23739 -4.03791,2.30136 -1.14598,1.06397 -2.05268,2.37637 -2.69275,3.80312 -1.28015,2.85349 -1.47719,6.11241 -0.96512,9.1977 0.66114,3.98343 2.44407,7.69333 4.46569,11.18873 2.27396,3.93169 4.918,7.71926 8.38442,10.65407 3.5985,3.04664 7.96161,5.07413 11.61053,8.0602"
|
||||
id="path14658-9"
|
||||
style="fill:none;stroke:#c17d11;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clipPath29644-8"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path29646-8"
|
||||
d="m 54.232441,122.36218 c -1.780966,0.097 -3.484616,0.91899 -4.787851,2.1367 -1.303235,1.21771 -2.221372,2.81176 -2.786181,4.50357 -1.129618,3.38363 -0.875481,7.05177 -0.618698,10.60973 0.23251,3.22162 0.470404,6.50533 1.676785,9.50158 0.60319,1.49813 1.450247,2.91021 2.580338,4.06395 1.130092,1.15374 2.551736,2.04189 4.118297,2.43447 1.468838,0.36809 3.038161,0.29183 4.482784,-0.16209 1.444623,-0.45391 2.763917,-1.27887 3.846236,-2.33791 1.57904,-1.54507 2.643262,-3.5662 3.253449,-5.68947 0.610186,-2.12328 0.784157,-4.35155 0.752401,-6.56053 -0.03974,-2.76435 -0.400909,-5.53851 -1.265755,-8.16439 -0.864846,-2.62588 -2.245742,-5.10327 -4.172795,-7.08561 -0.933308,-0.96009 -1.997766,-1.80513 -3.198586,-2.39747 -1.200819,-0.59233 -2.54344,-0.92535 -3.880424,-0.85253"
|
||||
style="fill:url(#radialGradient29648);fill-opacity:1;stroke:none" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="linearGradient28469-0">
|
||||
<stop
|
||||
style="stop-color:#d2940a;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop28479-4" />
|
||||
<stop
|
||||
style="stop-color:#d89c08;stop-opacity:1"
|
||||
offset="0.75143719"
|
||||
id="stop28477-2" />
|
||||
<stop
|
||||
id="stop28485-7"
|
||||
offset="0.86579126"
|
||||
style="stop-color:#b67e07;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop28473-1"
|
||||
offset="1"
|
||||
style="stop-color:#946106;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient28275-8">
|
||||
<stop
|
||||
id="stop28277-1"
|
||||
offset="0"
|
||||
style="stop-color:#ad780a;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#d89e08;stop-opacity:1"
|
||||
offset="0.11972899"
|
||||
id="stop28291-9" />
|
||||
<stop
|
||||
style="stop-color:#edb80b;stop-opacity:1"
|
||||
offset="0.25514477"
|
||||
id="stop28289-6" />
|
||||
<stop
|
||||
style="stop-color:#ebc80d;stop-opacity:1"
|
||||
offset="0.39194193"
|
||||
id="stop28287-6" />
|
||||
<stop
|
||||
style="stop-color:#f5d838;stop-opacity:1"
|
||||
offset="0.52741116"
|
||||
id="stop28285-7" />
|
||||
<stop
|
||||
style="stop-color:#f6d811;stop-opacity:1"
|
||||
offset="0.76906693"
|
||||
id="stop28283-7" />
|
||||
<stop
|
||||
id="stop28279-5"
|
||||
offset="1"
|
||||
style="stop-color:#f5cd31;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient29529-6">
|
||||
<stop
|
||||
id="stop29531-0"
|
||||
offset="0"
|
||||
style="stop-color:#3a2903;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#735208;stop-opacity:1"
|
||||
offset="0.55472803"
|
||||
id="stop29539-7" />
|
||||
<stop
|
||||
id="stop29533-8"
|
||||
offset="1"
|
||||
style="stop-color:#ac8c04;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient29477-3">
|
||||
<stop
|
||||
id="stop29479-5"
|
||||
offset="0"
|
||||
style="stop-color:#757574;stop-opacity:0" />
|
||||
<stop
|
||||
style="stop-color:#757574;stop-opacity:1;"
|
||||
offset="0.26291031"
|
||||
id="stop29487-5" />
|
||||
<stop
|
||||
style="stop-color:#757574;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop29485-0" />
|
||||
<stop
|
||||
id="stop29481-3"
|
||||
offset="1"
|
||||
style="stop-color:#757574;stop-opacity:0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient29336-6">
|
||||
<stop
|
||||
id="stop29338-1"
|
||||
offset="0"
|
||||
style="stop-color:#646464;stop-opacity:0" />
|
||||
<stop
|
||||
style="stop-color:#646464;stop-opacity:0.5825243"
|
||||
offset="0.30628255"
|
||||
id="stop29344-7" />
|
||||
<stop
|
||||
id="stop29354-5"
|
||||
offset="0.47000006"
|
||||
style="stop-color:#646464;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#646464;stop-opacity:0.25728154"
|
||||
offset="0.72834015"
|
||||
id="stop29356-3" />
|
||||
<stop
|
||||
id="stop29340-6"
|
||||
offset="1"
|
||||
style="stop-color:#646464;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient28976-3">
|
||||
<stop
|
||||
id="stop28978-7"
|
||||
offset="0"
|
||||
style="stop-color:#747474;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#8c8c8c;stop-opacity:1;"
|
||||
offset="0.125"
|
||||
id="stop29259-5" />
|
||||
<stop
|
||||
style="stop-color:#a4a4a4;stop-opacity:1;"
|
||||
offset="0.25"
|
||||
id="stop29257-0" />
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1"
|
||||
offset="0.5"
|
||||
id="stop28984-4" />
|
||||
<stop
|
||||
id="stop28986-0"
|
||||
offset="0.61919296"
|
||||
style="stop-color:#d4d4d4;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop28980-2"
|
||||
offset="1"
|
||||
style="stop-color:#7c7c7c;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="clipPath29028-5"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path29030-7"
|
||||
d="m 85.75,122.36218 c -2.780425,1.91023 -5.110569,4.57487 -6.25,7.75 -1.436029,4.00163 -0.885838,8.48071 0.5,12.5 1.419488,4.11688 3.793788,8.04098 7.37932,10.51234 1.792766,1.23567 3.868091,2.08301 6.030402,2.33859 2.162311,0.25558 4.409274,-0.0949 6.340278,-1.10093 2.35312,-1.22596 4.14782,-3.37278 5.26217,-5.78076 1.11436,-2.40798 1.5888,-5.0701 1.73783,-7.71924 0.18989,-3.37546 -0.14047,-6.80646 -1.25,-10 -1.20527,-3.46909 -3.39005,-6.67055 -6.472754,-8.6666 -1.541351,-0.99803 -3.291947,-1.68356 -5.110883,-1.93515 -1.818936,-0.25158 -3.704766,-0.0633 -5.416363,0.60175 -0.975471,0.37901 -1.887438,0.9074 -2.75,1.5"
|
||||
style="fill:url(#radialGradient29032);fill-opacity:1;stroke:none" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
id="linearGradient28935-8">
|
||||
<stop
|
||||
id="stop28937-7"
|
||||
offset="0"
|
||||
style="stop-color:#949494;stop-opacity:0.39215687;" />
|
||||
<stop
|
||||
style="stop-color:#949494;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop28943-3" />
|
||||
<stop
|
||||
id="stop28939-8"
|
||||
offset="1"
|
||||
style="stop-color:#949494;stop-opacity:0.39215687;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient28853-5">
|
||||
<stop
|
||||
id="stop28855-3"
|
||||
offset="0"
|
||||
style="stop-color:#020204;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#020204;stop-opacity:1"
|
||||
offset="0.73448181"
|
||||
id="stop28865-0" />
|
||||
<stop
|
||||
id="stop28857-9"
|
||||
offset="1"
|
||||
style="stop-color:#5c5c5c;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="clipPath20"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path18"
|
||||
d="M 0,0 H 1920 V 1080 H 0 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clipPath70"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path68"
|
||||
d="M 0,0 H 1920 V 1080 H 0 Z" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clipPath84"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<path
|
||||
id="path82"
|
||||
d="M 0,0 H 1920 V 1080 H 0 Z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
transform="translate(0,-1022.3182)"
|
||||
id="layer1">
|
||||
<path
|
||||
id="path5206"
|
||||
d=""
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
id="path5204"
|
||||
d=""
|
||||
style="fill:#000000" />
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g1740"
|
||||
transform="matrix(0.1420516,0,0,-0.1420516,103.61175,1146.9897)">
|
||||
<g
|
||||
transform="translate(-1082.1477,-40.602139)"
|
||||
style="stroke-width:9.38626099"
|
||||
id="g14">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g16"
|
||||
clip-path="url(#clipPath20)">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g22"
|
||||
transform="translate(485.7208,801.7501)">
|
||||
<path
|
||||
d="M 0,0 H -6.408 V 21.503 H 0 c 1.176,0 2.129,-0.953 2.129,-2.129 V 2.129 C 2.129,0.953 1.176,0 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path24" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g26"
|
||||
transform="translate(467.9097,852.7021)">
|
||||
<path
|
||||
d="m 0,0 -1.811,-1.811 -10.287,10.287 1.811,1.811 c 1.424,1.425 3.734,1.425 5.159,0 L 0,5.159 C 1.425,3.734 1.425,1.425 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path28" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g30"
|
||||
transform="translate(457.6224,762.014)">
|
||||
<path
|
||||
d="m 0,0 -1.811,1.811 10.287,10.287 1.811,-1.811 c 1.425,-1.425 1.425,-3.734 0,-5.159 L 5.159,0 C 3.734,-1.425 1.425,-1.425 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path32" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g34"
|
||||
transform="translate(449.515,753.7302)">
|
||||
<path
|
||||
d="m 0,0 v 4.934 c 0,0 -24.07,-8.855 -32.093,-8.855 -8.023,0 -32.093,8.855 -32.093,8.855 V 0 c 0,-2.713 0.889,-5.101 2.238,-6.509 1.433,-7.677 3.125,-26.35 3.681,-32.625 0,-4.333 2.261,-7.845 5.052,-7.845 h 42.245 c 2.79,0 5.051,3.512 5.051,7.845 v 10e-4 c 0.556,6.275 2.248,24.947 3.682,32.624 C -0.889,-5.101 0,-2.714 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path36" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g38"
|
||||
transform="translate(385.3291,871.2729)">
|
||||
<path
|
||||
d="m 0,0 v -4.934 c 0,0 24.07,8.855 32.093,8.855 8.023,0 32.093,-8.855 32.093,-8.855 V 0 c 0,2.713 -0.889,5.101 -2.238,6.509 -1.433,7.677 -3.125,26.35 -3.681,32.624 0,4.333 -2.261,7.846 -5.051,7.846 H 10.97 c -2.79,0 -5.051,-3.513 -5.051,-7.846 v 0 C 5.363,32.858 3.671,14.186 2.237,6.509 0.889,5.101 0,2.714 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path40" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g42"
|
||||
transform="translate(371.6938,858.2298)">
|
||||
<path
|
||||
d="m 0,0 c -25.255,-25.255 -25.255,-66.201 0,-91.456 25.255,-25.255 66.201,-25.255 91.456,0 25.256,25.255 25.255,66.201 0,91.456 C 66.201,25.255 25.255,25.255 0,0 m 85.935,-85.935 c -22.206,-22.205 -58.208,-22.205 -80.413,0 -22.206,22.206 -22.206,58.208 -0.001,80.414 22.206,22.205 58.208,22.205 80.414,0 22.206,-22.206 22.206,-58.208 0,-80.414"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path44" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
d="m -665.93071,765.84586 h 2.41 v -34.464 h -2.41 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path76" />
|
||||
<g
|
||||
transform="translate(-1082.1477,-40.602139)"
|
||||
style="stroke-width:9.38626099"
|
||||
id="g78">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g80"
|
||||
clip-path="url(#clipPath84)">
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g86"
|
||||
transform="translate(438.6725,783.7013)">
|
||||
<path
|
||||
d="m 0,0 c -1.568,-1.333 -3.448,-1.998 -5.643,-1.998 -3.761,0 -6.583,1.704 -8.464,5.113 l 2.058,1.235 c 0.666,-1.215 1.469,-2.156 2.409,-2.822 0.98,-0.744 2.312,-1.117 3.997,-1.117 3.683,0 5.525,1.567 5.525,4.703 0,1.371 -0.646,2.566 -1.939,3.585 -0.393,0.235 -0.951,0.5 -1.675,0.793 -0.726,0.294 -1.617,0.637 -2.675,1.029 -1.96,0.705 -3.37,1.411 -4.231,2.116 -1.255,1.019 -1.881,2.488 -1.881,4.408 0,1.646 0.626,3.057 1.881,4.232 1.214,1.214 2.8,1.822 4.76,1.822 2.704,0 4.996,-0.94 6.877,-2.821 L -0.764,18.75 c -1.332,1.332 -3.037,1.998 -5.114,1.998 -2.821,0 -4.232,-1.234 -4.232,-3.703 0,-1.097 0.431,-1.998 1.294,-2.703 0.705,-0.55 1.821,-1.079 3.35,-1.587 1.331,-0.471 2.429,-0.911 3.291,-1.323 0.862,-0.411 1.508,-0.774 1.94,-1.087 C 1.449,9.052 2.292,7.308 2.292,5.114 2.292,2.998 1.528,1.293 0,0"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path88" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path264"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
d="m -662.67221,771.89946 c 0,-1.134 -0.919,-2.053 -2.053,-2.053 -1.134,0 -2.054,0.919 -2.054,2.053 0,1.134 0.92,2.053 2.054,2.053 1.134,0 2.053,-0.919 2.053,-2.053" />
|
||||
<g
|
||||
style="stroke-width:9.38626099"
|
||||
id="g266"
|
||||
transform="translate(-662.03281,778.14876)">
|
||||
<path
|
||||
d="m 0,0 2.015,-1.321 21.656,33.028 -2.015,1.322 z"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.38626099"
|
||||
id="path268" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 2.8 KiB |
85
apps.json
|
@ -15,8 +15,8 @@
|
|||
{ "id": "moonphase",
|
||||
"name": "Moonphase",
|
||||
"icon": "app.png",
|
||||
"version":"0.01",
|
||||
"description": "Shows current moon phase. Currently only with fixed coordinates (northern hemisphere).",
|
||||
"version":"0.02",
|
||||
"description": "Shows current moon phase. Now with GPS function.",
|
||||
"tags": "",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
|
@ -91,7 +91,7 @@
|
|||
{ "id": "gbridge",
|
||||
"name": "Gadgetbridge",
|
||||
"icon": "app.png",
|
||||
"version":"0.04",
|
||||
"version":"0.06",
|
||||
"description": "The default notification handler for Gadgetbridge notifications from Android",
|
||||
"tags": "tool,system,android,widget",
|
||||
"storage": [
|
||||
|
@ -392,7 +392,8 @@
|
|||
{ "id": "swatch",
|
||||
"name": "Stopwatch",
|
||||
"icon": "stopwatch.png",
|
||||
"version":"0.03",
|
||||
"version":"0.05",
|
||||
"interface": "interface.html",
|
||||
"description": "Simple stopwatch with Lap Time logging to a JSON file",
|
||||
"tags": "health",
|
||||
"allow_emulator":true,
|
||||
|
@ -892,7 +893,7 @@
|
|||
{ "id": "marioclock",
|
||||
"name": "Mario Clock",
|
||||
"icon": "marioclock.png",
|
||||
"version":"0.04",
|
||||
"version":"0.05",
|
||||
"description": "Animated Mario clock, jumps to change the time!",
|
||||
"tags": "clock,mario,retro",
|
||||
"type": "clock",
|
||||
|
@ -963,7 +964,28 @@
|
|||
{"name":"chrono.img","url":"chrono-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "widhwt",
|
||||
{ "id": "astrocalc",
|
||||
"name": "Astrocalc",
|
||||
"icon": "astrocalc.png",
|
||||
"version":"0.01",
|
||||
"description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.",
|
||||
"tags": "app,sun,moon,cycles,tool,outdoors",
|
||||
"allow_emulator":true,
|
||||
"storage": [
|
||||
{"name":"astrocalc.app.js","url":"astrocalc-app.js"},
|
||||
{"name":"suncalc.js","url":"suncalc.js"},
|
||||
{"name":"astrocalc.img","url":"astrocalc-icon.js","evaluate":true},
|
||||
{"name":"first-quarter.img","url":"first-quarter-icon.js","evaluate":true},
|
||||
{"name":"last-quarter.img","url":"last-quarter-icon.js","evaluate":true},
|
||||
{"name":"waning-crescent.img","url":"waning-crescent-icon.js","evaluate":true},
|
||||
{"name":"waning-gibbous.img","url":"waning-gibbous-icon.js","evaluate":true},
|
||||
{"name":"full.img","url":"full-icon.js","evaluate":true},
|
||||
{"name":"new.img","url":"new-icon.js","evaluate":true},
|
||||
{"name":"waxing-gibbous.img","url":"waxing-gibbous-icon.js","evaluate":true},
|
||||
{"name":"waxing-crescent.img","url":"waxing-crescent-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "widhwt",
|
||||
"name": "Hand Wash Timer",
|
||||
"icon": "widget.png",
|
||||
"version":"0.01",
|
||||
|
@ -973,5 +995,56 @@
|
|||
"storage": [
|
||||
{"name":"widhwt.wid.js","url":"widget.js"}
|
||||
]
|
||||
},
|
||||
{ "id": "toucher",
|
||||
"name": "Touch Launcher",
|
||||
"shortName":"Menu",
|
||||
"icon": "app.png",
|
||||
"version":"0.02",
|
||||
"description": "Touch enable left to right launcher.",
|
||||
"tags": "tool,system,launcher",
|
||||
"type":"launch",
|
||||
"storage": [
|
||||
{"name":"toucher.app.js","url":"app.js"}
|
||||
],
|
||||
"sortorder" : -10
|
||||
},
|
||||
{
|
||||
"id": "balltastic",
|
||||
"name": "Balltastic",
|
||||
"icon": "app.png",
|
||||
"version": "0.01",
|
||||
"description": "Simple but fun ball eats dots game.",
|
||||
"tags": "game,fun",
|
||||
"type": "app",
|
||||
"storage": [
|
||||
{"name":"balltastic.app.js","url":"app.js"},
|
||||
{"name":"balltastic.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rpgdice",
|
||||
"name": "RPG dice",
|
||||
"icon": "rpgdice.png",
|
||||
"version": "0.01",
|
||||
"description": "Simple RPG dice rolling app.",
|
||||
"tags": "game,fun",
|
||||
"type": "app",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"rpgdice.app.js","url": "app.js"},
|
||||
{"name":"rpgdice.img","url": "app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "widmp",
|
||||
"name": "Moon Phase Widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.01",
|
||||
"description": "Display the current moon phase in blueish for the northern hemisphere in eight phases",
|
||||
"tags": "widget,tools",
|
||||
"type":"widget",
|
||||
"storage": [
|
||||
{"name":"widmp.wid.js","url":"widget.js"}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
0.01: Create astrocalc app
|
|
@ -0,0 +1,348 @@
|
|||
/**
|
||||
* Inspired by: https://www.timeanddate.com
|
||||
*/
|
||||
|
||||
const SunCalc = require("suncalc.js");
|
||||
|
||||
function drawMoon(phase, x, y) {
|
||||
const moonImgFiles = [
|
||||
"new",
|
||||
"waxing-crescent",
|
||||
"first-quarter",
|
||||
"waxing-gibbous",
|
||||
"full",
|
||||
"waning-gibbous",
|
||||
"last-quarter",
|
||||
"waning-crescent",
|
||||
];
|
||||
|
||||
img = require("Storage").read(`${moonImgFiles[phase]}.img`);
|
||||
// image width & height = 92px
|
||||
g.drawImage(img, x - parseInt(92 / 2), y);
|
||||
}
|
||||
|
||||
// linear interpolation between two values a and b
|
||||
// u controls amount of a/b and is in range [0.0,1.0]
|
||||
function lerp(a,b,u) {
|
||||
return (1-u) * a + u * b;
|
||||
}
|
||||
|
||||
function titlizeKey(key) {
|
||||
return (key[0].toUpperCase() + key.slice(1)).match(/[A-Z][a-z]+/g).join(" ");
|
||||
}
|
||||
|
||||
function dateToTimeString(date) {
|
||||
const hrs = ("0" + date.getHours()).substr(-2);
|
||||
const mins = ("0" + date.getMinutes()).substr(-2);
|
||||
const secs = ("0" + date.getMinutes()).substr(-2);
|
||||
|
||||
return `${hrs}:${mins}:${secs}`;
|
||||
}
|
||||
|
||||
function drawTitle(key) {
|
||||
const fontHeight = 16;
|
||||
const x = 0;
|
||||
const x2 = g.getWidth() - 1;
|
||||
const y = fontHeight + 26;
|
||||
const y2 = g.getHeight() - 1;
|
||||
const title = titlizeKey(key);
|
||||
|
||||
g.setFont("6x8", 2);
|
||||
g.setFontAlign(0,-1);
|
||||
g.drawString(title,(x+x2)/2,y-fontHeight-2);
|
||||
g.drawLine(x,y-2,x2,y-2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @params {Number} angle Angle of point around a radius
|
||||
* @params {Number} radius Radius of the point to be drawn, default 2
|
||||
* @params {Object} color Color of the point
|
||||
* @params {Number} color.r Red 0-1
|
||||
* @params {Number} color.g Green 0-1
|
||||
* @params {Number} color.b Blue 0-1
|
||||
*/
|
||||
function drawPoint(angle, radius, color) {
|
||||
const pRad = Math.PI / 180;
|
||||
const faceWidth = 80; // watch face radius
|
||||
const centerPx = g.getWidth() / 2;
|
||||
|
||||
const a = angle * pRad;
|
||||
const x = centerPx + Math.sin(a) * faceWidth;
|
||||
const y = centerPx - Math.cos(a) * faceWidth;
|
||||
|
||||
if (!radius) radius = 2;
|
||||
|
||||
g.setColor(color.r, color.g, color.b);
|
||||
g.fillCircle(x, y + 20, radius);
|
||||
}
|
||||
|
||||
function drawPoints() {
|
||||
const startColor = {r: 140, g: 255, b: 255}; // light blue
|
||||
const endColor = {r: 0, g: 0, b: 140}; // dark turquoise
|
||||
|
||||
const steps = 60;
|
||||
const step_u = 1.0 / (steps / 2);
|
||||
let u = 0.0;
|
||||
|
||||
for (let i = 0; i < steps; i++) {
|
||||
const colR = lerp(startColor.r, endColor.r, u) / 255;
|
||||
const colG = lerp(startColor.g, endColor.g, u) / 255;
|
||||
const colB = lerp(startColor.b, endColor.b, u) / 255;
|
||||
const col = {r: colR, g: colG, b: colB};
|
||||
|
||||
if (i >= 0 && i <= 30) {
|
||||
u += step_u;
|
||||
} else {
|
||||
u -= step_u;
|
||||
}
|
||||
|
||||
drawPoint((360 * i) / steps, 2, col);
|
||||
}
|
||||
}
|
||||
|
||||
function drawData(title, obj, startX, startY) {
|
||||
g.clear();
|
||||
drawTitle(title);
|
||||
|
||||
let xPos, yPos;
|
||||
|
||||
if (typeof(startX) === "undefined" || startX === null) {
|
||||
// Center text
|
||||
g.setFontAlign(0,-1);
|
||||
xPos = (0 + g.getWidth() - 2) / 2;
|
||||
} else {
|
||||
xPos = startX;
|
||||
}
|
||||
|
||||
if (typeof(startY) === "undefined") {
|
||||
yPos = 5;
|
||||
} else {
|
||||
yPos = startY;
|
||||
}
|
||||
|
||||
g.setFont("6x8", 1);
|
||||
|
||||
Object.keys(obj).forEach((key) => {
|
||||
g.drawString(`${key}: ${obj[key]}`, xPos, yPos += 20);
|
||||
});
|
||||
|
||||
g.flip();
|
||||
}
|
||||
|
||||
function drawMoonPositionPage(gps, title) {
|
||||
const pos = SunCalc.getMoonPosition(new Date(), gps.lat, gps.lon);
|
||||
|
||||
const pageData = {
|
||||
Azimuth: pos.azimuth.toFixed(2),
|
||||
Altitude: pos.altitude.toFixed(2),
|
||||
Distance: `${pos.distance.toFixed(0)} km`,
|
||||
"Parallactic Ang": pos.parallacticAngle.toFixed(2),
|
||||
};
|
||||
const azimuthDegrees = parseInt(pos.azimuth * 180 / Math.PI);
|
||||
|
||||
drawData(title, pageData, null, 80);
|
||||
drawPoints();
|
||||
drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 1});
|
||||
|
||||
let m = setWatch(() => {
|
||||
let m = moonIndexPageMenu(gps);
|
||||
}, BTN3, {repeat: false, edge: "falling"});
|
||||
}
|
||||
|
||||
function drawMoonIlluminationPage(gps, title) {
|
||||
const phaseNames = [
|
||||
"New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous",
|
||||
"Full Moon", "Waning Gibbous", "Last Quater", "Waning Crescent",
|
||||
];
|
||||
|
||||
const phase = SunCalc.getMoonIllumination(new Date());
|
||||
const pageData = {
|
||||
Phase: phaseNames[phase.phase],
|
||||
};
|
||||
|
||||
drawData(title, pageData, null, 35);
|
||||
drawMoon(phase.phase, g.getWidth() / 2, g.getHeight() / 2);
|
||||
|
||||
let m = setWatch(() => {
|
||||
let m = moonIndexPageMenu(gps);
|
||||
}, BTN3, {repease: false, edge: "falling"});
|
||||
}
|
||||
|
||||
|
||||
function drawMoonTimesPage(gps, title) {
|
||||
const times = SunCalc.getMoonTimes(new Date(), gps.lat, gps.lon);
|
||||
|
||||
const pageData = {
|
||||
Rise: dateToTimeString(times.rise),
|
||||
Set: dateToTimeString(times.set),
|
||||
};
|
||||
|
||||
drawData(title, pageData, null, 105);
|
||||
drawPoints();
|
||||
|
||||
// Draw the moon rise position
|
||||
const risePos = SunCalc.getMoonPosition(times.rise, gps.lat, gps.lon);
|
||||
const riseAzimuthDegrees = parseInt(risePos.azimuth * 180 / Math.PI);
|
||||
drawPoint(riseAzimuthDegrees, 8, {r: 1, g: 1, b: 1});
|
||||
|
||||
// Draw the moon set position
|
||||
const setPos = SunCalc.getMoonPosition(times.set, gps.lat, gps.lon);
|
||||
const setAzimuthDegrees = parseInt(setPos.azimuth * 180 / Math.PI);
|
||||
drawPoint(setAzimuthDegrees, 8, {r: 1, g: 1, b: 1});
|
||||
|
||||
let m = setWatch(() => {
|
||||
let m = moonIndexPageMenu(gps);
|
||||
}, BTN3, {repease: false, edge: "falling"});
|
||||
}
|
||||
|
||||
function drawSunShowPage(gps, key, date) {
|
||||
const pos = SunCalc.getPosition(date, gps.lat, gps.lon);
|
||||
|
||||
const hrs = ("0" + date.getHours()).substr(-2);
|
||||
const mins = ("0" + date.getMinutes()).substr(-2);
|
||||
const secs = ("0" + date.getMinutes()).substr(-2);
|
||||
const time = `${hrs}:${mins}:${secs}`;
|
||||
|
||||
const azimuth = Number(pos.azimuth.toFixed(2));
|
||||
const azimuthDegrees = parseInt(pos.azimuth * 180 / Math.PI);
|
||||
const altitude = Number(pos.altitude.toFixed(2));
|
||||
|
||||
const pageData = {
|
||||
Time: time,
|
||||
Altitude: altitude,
|
||||
Azimumth: azimuth,
|
||||
Degrees: azimuthDegrees
|
||||
};
|
||||
|
||||
drawData(key, pageData, null, 85);
|
||||
|
||||
drawPoints();
|
||||
|
||||
// Draw the suns position
|
||||
drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 0});
|
||||
|
||||
m = setWatch(() => {
|
||||
m = sunIndexPageMenu(gps);
|
||||
}, BTN3, {repeat: false, edge: "falling"});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function sunIndexPageMenu(gps) {
|
||||
const sunTimes = SunCalc.getTimes(new Date(), gps.lat, gps.lon);
|
||||
|
||||
const sunMenu = {
|
||||
"": {
|
||||
"title": "-- Sun --",
|
||||
},
|
||||
"Current Pos": () => {
|
||||
m = E.showMenu();
|
||||
drawSunShowPage(gps, "Current Pos", new Date());
|
||||
},
|
||||
};
|
||||
|
||||
Object.keys(sunTimes).sort().reduce((menu, key) => {
|
||||
const title = titlizeKey(key);
|
||||
menu[title] = () => {
|
||||
m = E.showMenu();
|
||||
drawSunShowPage(gps, key, sunTimes[key]);
|
||||
};
|
||||
return menu;
|
||||
}, sunMenu);
|
||||
|
||||
sunMenu["< Back"] = () => m = indexPageMenu(gps);
|
||||
|
||||
return E.showMenu(sunMenu);
|
||||
}
|
||||
|
||||
|
||||
function moonIndexPageMenu(gps) {
|
||||
const moonMenu = {
|
||||
"": {
|
||||
"title": "-- Moon --",
|
||||
},
|
||||
"Times": () => {
|
||||
m = E.showMenu();
|
||||
drawMoonTimesPage(gps, "Times");
|
||||
},
|
||||
"Position": () => {
|
||||
m = E.showMenu();
|
||||
drawMoonPositionPage(gps, "Position");
|
||||
},
|
||||
"Illumination": () => {
|
||||
m = E.showMenu();
|
||||
drawMoonIlluminationPage(gps, "Illumination");
|
||||
},
|
||||
"< Back": () => m = indexPageMenu(gps),
|
||||
};
|
||||
|
||||
return E.showMenu(moonMenu);
|
||||
}
|
||||
|
||||
function indexPageMenu(gps) {
|
||||
const menu = {
|
||||
"": {
|
||||
"title": "Select",
|
||||
},
|
||||
"Sun": () => {
|
||||
m = sunIndexPageMenu(gps);
|
||||
},
|
||||
"Moon": () => {
|
||||
m = moonIndexPageMenu(gps);
|
||||
},
|
||||
"< Exit": () => { load(); }
|
||||
};
|
||||
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* GPS wait page, shows GPS locating animation until it gets a lock, then moves to the Sun page
|
||||
*/
|
||||
function drawGPSWaitPage() {
|
||||
const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA=="))
|
||||
|
||||
g.clear();
|
||||
g.drawImage(img, 100, 50);
|
||||
g.setFont("6x8", 1);
|
||||
g.drawString("Astrocalc v0.01", 80, 105);
|
||||
g.drawString("Locating GPS", 85, 140);
|
||||
g.drawString("Please wait...", 80, 155);
|
||||
g.flip();
|
||||
|
||||
const DEBUG = false;
|
||||
if (DEBUG) {
|
||||
const gps = {
|
||||
"lat": 56.45783133333,
|
||||
"lon": -3.02188583333,
|
||||
"alt": 75.3,
|
||||
"speed": 0.070376,
|
||||
"course": NaN,
|
||||
"time":new Date(),
|
||||
"satellites": 4,
|
||||
"fix": 1
|
||||
};
|
||||
|
||||
m = indexPageMenu(gps);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Bangle.on('GPS', (gps) => {
|
||||
if (gps.fix === 0) return;
|
||||
|
||||
Bangle.setGPSPower(0);
|
||||
Bangle.buzz();
|
||||
Bangle.setLCDPower(true);
|
||||
|
||||
m = indexPageMenu(gps);
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
Bangle.setGPSPower(1);
|
||||
drawGPSWaitPage();
|
||||
}
|
||||
|
||||
let m;
|
||||
init();
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA=="))
|
After Width: | Height: | Size: 952 B |
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgI1ygf4BZM/BZMD//wCxP/8AWJ/+ACxP+CxQ6ICwP/4AWJERAWCEQ4WCERAWCEQ4WDOg4WCNA4WD/gWKRYwWDHI4WDHIwWDHI4WDHIwWEOYwWDHIwWEKAwWD/4WKKAwWEKAoWEYgwWPM4wWEM4oWQM4oWEPwwWbPwoWESowW/C34WOZ1vACxP8Cyv4CxWACyoKFCwiUFCwhmGCwh9FCwhmGCwhmFCwhPGCwgKFCwg4GCwZPGCwg4GCwY4GCwgKGCwY4GCwZxGCwjBFCwghHCwQhHCwYhHCwQhHCwRlHCwSHHCwYKICwI3HCwQKJAFAA=="))
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgJC/AD8B//4BRILJBQP/+AKGn4LC4AKFh4KC/4KFgYKD/gLFv4LD8AKEj4KD/+AEJAiGEIgiFIYhFFOAQADOghlDNA0HBQv+Q4wADRYZaFLgg4GHIg4GHIY4GHIhxFOYhxGOYgKHKARPHKARPHKAZPHKATBFYgoWKMw5nDMw5nCCyx9IPwQKIPwIW/C34WJZ1sDBQ/8CwM/BY/ACxkfBY+AgEBBQ/4CwJ+IBQJ+IPoJnIMwRnIMwJQIJ4RQIJ4JQIJ4RQIBQQ5HHAQ5HHAY5HHARzHOIRzHOIbEHYIIACLgpaDEQwhFEQohEIopDENAplERYwKGOgZwEBYoKIAH4AXA=="))
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgI0xgP8BRP/4ALI/4WJv4WJj4WJg//CxA3BCxM/CxIhCCw4hCCxAhCCw4hCCxAKCCw5lBCxEDCxSHBCxA4DCw4KCCw44DCww4DCw5xCCw44DCw5PDCw0PCxQKDCwxPDCwzBDCyRmECwxmDCyRmDCwx9ECzoKDCwyUEC34W/CyDOtn4WJgYWVgIWKj4WVPwgWFSogWGM4gWGPwYWGM4gWGM4YWGKAgWGKAYWGHIgWGKAYWHHIYWGHIYWHHIYWGHIYWHOYYWHYgQWHEQYWHEQQWIEQQWHEQQWINAQWIRYIWIOgQWIHQIWJBYIWJAFI="))
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgIGDh///4RHBQQLHg4KC/wKFgIKC//4BYt/BYfgBQkfBQf/wAsHFw4HCBwXwBQc/AwYLB4AhEIARIBEQn//gECgYiEIYJ2FIoQQBE4YzBDgd/NoguBNAUPKoo/BB4YhEEQIdCAYYiECQMHUwwHDEIweBLgMPWIwiBAQSlENwQTBDIQAFFQMDHAw5BOYN/HAwfB8ANCAAofCHA45B+EPHA4UBKQQAGMgMfUYQAFv+DJ45QCn5PHKAPDJ45QB/hmICwPnT4yhC/1/Mw5nBCxZmIM4P/PpB+BC34WEVZCsB/7CIYYIWWOX4WbfiwWL/gKHgf+n/ABY8/4YWJ/k/VhF/4LDIg/4j5nI/+APxEP+EPM48BCgN/KA5CBg5QHMwINCJ4/AgY5Hh4fBj45GHAKeBAQSfFMgIZCHAoqCv45GA4QOBEQsfDwQDDEIgSC/4iFv6dCg4iFj60Dn4iEEIKRCL4K5E/5uDh4QDDgKFEv4uDj4/EE4IRCDYIzEAwIvBAQKnFEQIADMIhFBAAayFNAIACMoZtDBYa9GFwbrHBQR2EBYoKEA=="))
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
(c) 2011-2015, Vladimir Agafonkin
|
||||
SunCalc is a JavaScript library for calculating sun/moon position and light phases.
|
||||
https://github.com/mourner/suncalc
|
||||
*/
|
||||
|
||||
(function () { 'use strict';
|
||||
|
||||
// shortcuts for easier to read formulas
|
||||
|
||||
var PI = Math.PI,
|
||||
sin = Math.sin,
|
||||
cos = Math.cos,
|
||||
tan = Math.tan,
|
||||
asin = Math.asin,
|
||||
atan = Math.atan2,
|
||||
acos = Math.acos,
|
||||
rad = PI / 180;
|
||||
|
||||
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
|
||||
|
||||
|
||||
// date/time constants and conversions
|
||||
|
||||
var dayMs = 1000 * 60 * 60 * 24,
|
||||
J1970 = 2440588,
|
||||
J2000 = 2451545;
|
||||
|
||||
function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
|
||||
function fromJulian(j) { return (j + 0.5 - J1970) * dayMs; }
|
||||
function toDays(date) { return toJulian(date) - J2000; }
|
||||
|
||||
|
||||
// general calculations for position
|
||||
|
||||
var e = rad * 23.4397; // obliquity of the Earth
|
||||
|
||||
function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
|
||||
function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
|
||||
|
||||
function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
|
||||
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
|
||||
|
||||
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
|
||||
|
||||
function astroRefraction(h) {
|
||||
if (h < 0) // the following formula works for positive altitudes only.
|
||||
h = 0; // if h = -0.08901179 a div/0 would occur.
|
||||
|
||||
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
|
||||
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
|
||||
}
|
||||
|
||||
// general sun calculations
|
||||
|
||||
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
|
||||
|
||||
function eclipticLongitude(M) {
|
||||
|
||||
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
|
||||
P = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return M + C + P + PI;
|
||||
}
|
||||
|
||||
function sunCoords(d) {
|
||||
|
||||
var M = solarMeanAnomaly(d),
|
||||
L = eclipticLongitude(M);
|
||||
|
||||
return {
|
||||
dec: declination(L, 0),
|
||||
ra: rightAscension(L, 0)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var SunCalc = {};
|
||||
|
||||
|
||||
// calculates sun position for a given date and latitude/longitude
|
||||
|
||||
SunCalc.getPosition = function (date, lat, lng) {
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
d = toDays(date),
|
||||
|
||||
c = sunCoords(d),
|
||||
H = siderealTime(d, lw) - c.ra;
|
||||
|
||||
return {
|
||||
azimuth: azimuth(H, phi, c.dec),
|
||||
altitude: altitude(H, phi, c.dec)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// sun times configuration (angle, morning name, evening name)
|
||||
|
||||
var times = SunCalc.times = [
|
||||
[-0.833, 'sunrise', 'sunset' ],
|
||||
[ -0.3, 'sunriseEnd', 'sunsetStart' ],
|
||||
[ -6, 'dawn', 'dusk' ],
|
||||
[ -12, 'nauticalDawn', 'nauticalDusk'],
|
||||
[ -18, 'nightEnd', 'night' ],
|
||||
[ 6, 'goldenHourEnd', 'goldenHour' ]
|
||||
];
|
||||
|
||||
// adds a custom time to the times config
|
||||
|
||||
SunCalc.addTime = function (angle, riseName, setName) {
|
||||
times.push([angle, riseName, setName]);
|
||||
};
|
||||
|
||||
|
||||
// calculations for sun times
|
||||
|
||||
var J0 = 0.0009;
|
||||
|
||||
function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); }
|
||||
|
||||
function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; }
|
||||
function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); }
|
||||
|
||||
function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); }
|
||||
function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; }
|
||||
|
||||
// returns set time for the given sun altitude
|
||||
function getSetJ(h, lw, phi, dec, n, M, L) {
|
||||
|
||||
var w = hourAngle(h, phi, dec),
|
||||
a = approxTransit(w, lw, n);
|
||||
return solarTransitJ(a, M, L);
|
||||
}
|
||||
|
||||
|
||||
// calculates sun times for a given date, latitude/longitude, and, optionally,
|
||||
// the observer height (in meters) relative to the horizon
|
||||
|
||||
SunCalc.getTimes = function (date, lat, lng, height) {
|
||||
|
||||
height = height || 0;
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
|
||||
dh = observerAngle(height),
|
||||
|
||||
d = toDays(date),
|
||||
n = julianCycle(d, lw),
|
||||
ds = approxTransit(0, lw, n),
|
||||
|
||||
M = solarMeanAnomaly(ds),
|
||||
L = eclipticLongitude(M),
|
||||
dec = declination(L, 0),
|
||||
|
||||
Jnoon = solarTransitJ(ds, M, L),
|
||||
|
||||
i, len, time, h0, Jset, Jrise;
|
||||
|
||||
|
||||
var result = {
|
||||
solarNoon: new Date(fromJulian(Jnoon)),
|
||||
nadir: new Date(fromJulian(Jnoon - 0.5))
|
||||
};
|
||||
|
||||
for (i = 0, len = times.length; i < len; i += 1) {
|
||||
time = times[i];
|
||||
h0 = (time[0] + dh) * rad;
|
||||
|
||||
Jset = getSetJ(h0, lw, phi, dec, n, M, L);
|
||||
Jrise = Jnoon - (Jset - Jnoon);
|
||||
|
||||
result[time[1]] = new Date(fromJulian(Jrise) - (dayMs / 2));
|
||||
result[time[2]] = new Date(fromJulian(Jset) + (dayMs / 2));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
|
||||
|
||||
function moonCoords(d) { // geocentric ecliptic coordinates of the moon
|
||||
|
||||
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
|
||||
M = rad * (134.963 + 13.064993 * d), // mean anomaly
|
||||
F = rad * (93.272 + 13.229350 * d), // mean distance
|
||||
|
||||
l = L + rad * 6.289 * sin(M), // longitude
|
||||
b = rad * 5.128 * sin(F), // latitude
|
||||
dt = 385001 - 20905 * cos(M); // distance to the moon in km
|
||||
|
||||
return {
|
||||
ra: rightAscension(l, b),
|
||||
dec: declination(l, b),
|
||||
dist: dt
|
||||
};
|
||||
}
|
||||
|
||||
SunCalc.getMoonPosition = function (date, lat, lng) {
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
d = toDays(date),
|
||||
|
||||
c = moonCoords(d),
|
||||
H = siderealTime(d, lw) - c.ra,
|
||||
h = altitude(H, phi, c.dec),
|
||||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
|
||||
|
||||
h = h + astroRefraction(h); // altitude correction for refraction
|
||||
|
||||
return {
|
||||
azimuth: azimuth(H, phi, c.dec),
|
||||
altitude: h,
|
||||
distance: c.dist,
|
||||
parallacticAngle: pa
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// calculations for illumination parameters of the moon,
|
||||
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
|
||||
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
|
||||
// Function updated from gist: https://gist.github.com/endel/dfe6bb2fbe679781948c
|
||||
|
||||
SunCalc.getMoonIllumination = function (date) {
|
||||
let month = date.getMonth();
|
||||
let year = date.getFullYear();
|
||||
let day = date.getDate();
|
||||
|
||||
let c = 0;
|
||||
let e = 0;
|
||||
let jd = 0;
|
||||
let b = 0;
|
||||
|
||||
if (month < 3) {
|
||||
year--;
|
||||
month += 12;
|
||||
}
|
||||
|
||||
++month;
|
||||
c = 365.25 * year;
|
||||
e = 30.6 * month;
|
||||
jd = c + e + day - 694039.09; // jd is total days elapsed
|
||||
jd /= 29.5305882; // divide by the moon cycle
|
||||
b = parseInt(jd); // int(jd) -> b, take integer part of jd
|
||||
jd -= b; // subtract integer part to leave fractional part of original jd
|
||||
b = Math.round(jd * 8); // scale fraction from 0-8 and round
|
||||
|
||||
if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0
|
||||
|
||||
return {phase: b};
|
||||
};
|
||||
|
||||
|
||||
function hoursLater(date, h) {
|
||||
return new Date(date.valueOf() + h * dayMs / 24);
|
||||
}
|
||||
|
||||
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
|
||||
|
||||
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
|
||||
var t = date;
|
||||
if (inUTC) t.setUTCHours(0, 0, 0, 0);
|
||||
else t.setHours(0, 0, 0, 0);
|
||||
|
||||
var hc = 0.133 * rad,
|
||||
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
|
||||
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
|
||||
|
||||
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
|
||||
for (var i = 1; i <= 24; i += 2) {
|
||||
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
|
||||
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
|
||||
|
||||
a = (h0 + h2) / 2 - h1;
|
||||
b = (h2 - h0) / 2;
|
||||
xe = -b / (2 * a);
|
||||
ye = (a * xe + b) * xe + h1;
|
||||
d = b * b - 4 * a * h1;
|
||||
roots = 0;
|
||||
|
||||
if (d >= 0) {
|
||||
dx = Math.sqrt(d) / (Math.abs(a) * 2);
|
||||
x1 = xe - dx;
|
||||
x2 = xe + dx;
|
||||
if (Math.abs(x1) <= 1) roots++;
|
||||
if (Math.abs(x2) <= 1) roots++;
|
||||
if (x1 < -1) x1 = x2;
|
||||
}
|
||||
|
||||
if (roots === 1) {
|
||||
if (h0 < 0) rise = i + x1;
|
||||
else set = i + x1;
|
||||
|
||||
} else if (roots === 2) {
|
||||
rise = i + (ye < 0 ? x2 : x1);
|
||||
set = i + (ye < 0 ? x1 : x2);
|
||||
}
|
||||
|
||||
if (rise && set) break;
|
||||
|
||||
h0 = h2;
|
||||
}
|
||||
|
||||
var result = {};
|
||||
|
||||
if (rise) result.rise = hoursLater(t, rise);
|
||||
if (set) result.set = hoursLater(t, set);
|
||||
|
||||
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// export as Node module / AMD module / browser variable
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc;
|
||||
else if (typeof define === 'function' && define.amd) define(SunCalc);
|
||||
else global.SunCalc = SunCalc;
|
||||
|
||||
}());
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgJC/ABHgBRN8BRMfwAKIg/4CxP/BRM/HBMH/wKIgP/4AhJ/ghJ/5PJ/5PJj4WJgf/+AWIv5mJHAIWJ/5mJHAJ9IHAIWJn59JHAJ9JJ4IWIh4WK/4WJJ4KUIYIKUJJ4IWIMwIWgMwIWIPoLCJCwLCICxYKBCxCUBC34W/Cya3WCxr8In78JgYWhj4WJgIWKPwP8SpXAM5IWJPwIWIKAIWJM4PgKBP+CxBQBCxA5CBRBQBYZA5CBRA5BSpA5CSpA5BCxJzBPxDEBPxIiBM5MDPxJFBM5IiBKBMBKBKLBKBMAhwKJAH4ABA="))
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgI0xgP/wAKJ/wWI///+AKHv4LBEQ8fBQP8BQ0HBQP/8A3HAAQWGn4KCHIwhDHIwhE/AhJ//AEJJQGBQZQGMoQABRQsDCwhQFQ4RnHHAgWGBQhnFHAhnFHAoWFOIhnFHAp+FJ4oWEh4WKBQp+EJ4qVEYIgWRMwwWEMwoWLVghmFVgh9GCzYKGCwaUGC34W/CxzOtn4WJgYKF/wWK8AKCgIWKj4WVPwwWDSo38BQZnG4B+JCwhnGCwhnF/AKDKA2AKBIWEHIwKEKAqrDHI4KEHIp9EHIqUEHIxmEOYp9EYgxmEEQpmFEQoKFEQhmFEQhPGNAhPFRYg4GOggKHHQSIFBYghIAFQ="))
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgJC/ABdwBRMD8ALJj+ABREB/wWJh/wBZN/4AKIg4iKn/4KBP/ERMfERMB/5FJj//NBP//hnJ/6LJ/45Jg45Kv45JCwI5Jn5zJPwI5JCwJQICwP/CxRQISoJQJSoLEICwRQICwJnICzJnIYYJ+JCzB+ICwKVJC34W/CxbOffgIWIfgXACxP8Cyv4CxWACyUDPpU/ShIWBPpIWBPpEHMxMAv5mJCwJPICwQKIYQI4IYQJPJCwI4ISgI4JSgIKICwI4Jn5xJSgLBIMwIhJg4hJMwIKJj4hJgJlJgE+BRMHBRIA+A"))
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("rlcgI1yj/4BREH/4LJ/4LJj4LB8AKGgYKB/+ABY1/BQP+BQ0PCwQuHBQX/4A4IEQ8BCwYiGn4iJJ4YiHJ4QAB+CIGAAZoFBQn8MxCLHBQg5FMwY5GMwg5GCwo5EMwhzGPog5FCwxQECwv/PpJQFSghQFCwzEECyJnECwxnDVYoWFBQpnECwx+ECzp+DCwyVEC34W/CyDOt4AKCg4KF/gWDv4WQ/AWKwAWVBQcDShMAn5mJCwx9DCwxmEgJmJgEfJ5IWGBQasGHAisFJ4gWGHAh+FHAiVGBQhnFHAp+EOIhnGYIZnGEIpQEEIxnEEIpQEEIxQDMoo5EQ4o5FFgyKDBRAiBBRAApA="))
|
|
@ -0,0 +1 @@
|
|||
0.01: Initial version of Balltastic released! Happy!
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwkEogAIkUzmciBpIVIkYWBAAUyCx0hiIXFAAMkCxhUBC4fzDAYWLiAXFAAP//5KKoMRC4UTC4k/DAPzJJERiKcCC5H/GA4uBWwp6DC4YwHCwMBDI0SMAYwHoIWBiXxdIwYCMJCjBiM/C46VDC4M/GAkRgMf//ySAQAEgKrDC4lBgMCHIQXHSwxICIwIuBAAIXIGAYABiQXBkEBTYcgC473FkQXBiETTQZ4IgECC4cholCiJGDMAIXIWgIXCmMkC4JGDJBbEDC4UACwn/mAtGSYsxilCgIXFSAqDBkMRiIFBkcxiUiC4sxXowIBC4QGBkIXBiJ2EFwsDBIPyC4ILBgMRiUyiCmJgSCC+YXDgAXDR4YuEcAn/MAIXEmcgBoXyFwjIEMAQXFkIOCUgoXF+J3CC4cxBwR1IQQx3BkUzmUSBQKkFC5IuBkVDJAJeGRwLhHFwUkC4Mxl6lFC48gFwYXCmcTOwomBC4swYIMikU0C4UxkJ3FC40xFoIXCogXBmaxDC5MyCwUiogXDmIXTJASSBC4kRU4oXDkgXFmQwDNwIWEBoIXFJAYKBZggWFC4YWCC4g7BkIWBkYWBBYYXCkYXDJAYjDkQUEEYZGEGA4XIIwwwGDAQuOGAomCFo4uGGARoBE4ZOGFxAABBwgAICxAABCyxJBGJJFJJRgVNPggsMA="))
|
|
@ -0,0 +1,186 @@
|
|||
Bangle.setLCDBrightness(1);
|
||||
Bangle.setLCDMode("doublebuffered");
|
||||
|
||||
let points = 0;
|
||||
let level = 1;
|
||||
let levelSpeedStart = 0.8;
|
||||
let nextLevelPoints = 20;
|
||||
let levelSpeedFactor = 0.2;
|
||||
let counterWidth = 10;
|
||||
let gWidth = g.getWidth() - counterWidth;
|
||||
let gHeight = g.getHeight();
|
||||
let counter = 160;
|
||||
let counterMax = 160;
|
||||
let ballDims = 20;
|
||||
let ballx = g.getWidth() / 2 - ballDims;
|
||||
let bally = g.getHeight() / 2 - ballDims;
|
||||
let dotx = g.getWidth() / 2;
|
||||
let doty = g.getWidth() / 2;
|
||||
let ballBuzzTime = 5;
|
||||
let ballSpeedFactor = 40;
|
||||
let redrawspeed = 5;
|
||||
let dotwidth = 5;
|
||||
let running = false;
|
||||
let drawInterval;
|
||||
let xBuzzed = false;
|
||||
let yBuzzed = false;
|
||||
|
||||
let BALL = require("heatshrink").decompress(
|
||||
atob(
|
||||
"ikUyAROvkQ3v4405AIYHBGq9KpMhktz1/W7feAJAtBEZ9jhkhs0ZgkQ8lKxW+jAdB516627E4X8AIPWzelmolKlpJBjMFEYIpC4kQ0YBBqWKynTFYPe7gpE3ec6gnHkNFrXL7372u2E4WjhGCAIliqWrUIPeKoIpB7h9HoUoqWq999///FIJ3BhGDEIIBBgFBAoWCoUI3vY62aQIW7ymSJooLBEoIADwkQEYVhEoInEGIOjR4O1y/OrIrBUYdr198iH/74nF88cE4gpCA4MY8k59CzBAINrx2164nBtduufPWYIlF++/xkxNoMAAIJPBoSdB52a30ZkNGE4IvBoUpwkxLIOMyWEmAmE7+MqKbEsLLBH4P3zw1BAYJFBFIMY8sQ4cx44nB0tVHYITBEoO967lDgDDC1tVQ4QBD37xBjMmJ4I3BE4IxBPoOMuSrBHYL1BJYbrDvfPLoYBD889jMlEoMhkpJBwkRE4O+jB7B405LoJPEYYUx0xPG7/3vxvBmOnrXsdIOc6jxBE4JfBvfwHIafDFoMRgh3H99+zsUDIOMqWU2YlBAAO1/AnBToN76EhgpTBFYKPBGIIhBEovOrWliuc2YlBE4oABE4etu2UyVrpqJBMoKvBEIPnjvWze97ATBE4YPBEopRC64BC27nBzn0znTAIOlimtq21y4BCEoM1HYOMqIVBE44AB0tVCYIBEigVBE4U1GYIFBymywkwEoJzHABIRBMIIXBWoIDCqOEmOEiABCmIjPAA51BFoVSEoUwAIIZNA"
|
||||
)
|
||||
);
|
||||
|
||||
function reset() {
|
||||
g.clear();
|
||||
level = 1;
|
||||
points = 0;
|
||||
ballx = g.getWidth() / 2 - ballDims;
|
||||
bally = g.getHeight() / 2 - ballDims;
|
||||
counter = counterMax;
|
||||
createRandomDot();
|
||||
drawInterval = setInterval(play, redrawspeed);
|
||||
running = true;
|
||||
}
|
||||
|
||||
function collide() {
|
||||
try {
|
||||
Bangle.buzz(ballBuzzTime, 0.8);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function createRandomDot() {
|
||||
dotx = Math.floor(
|
||||
Math.random() * Math.floor(gWidth - dotwidth / 2) + dotwidth / 2
|
||||
);
|
||||
doty = Math.floor(
|
||||
Math.random() * Math.floor(gHeight - dotwidth / 2) + dotwidth / 2
|
||||
);
|
||||
}
|
||||
|
||||
function checkIfDotEaten() {
|
||||
if (
|
||||
ballx + ballDims > dotx &&
|
||||
ballx <= dotx + dotwidth &&
|
||||
bally + ballDims > doty &&
|
||||
bally <= doty + dotwidth
|
||||
) {
|
||||
collide();
|
||||
createRandomDot();
|
||||
counter = counterMax;
|
||||
points++;
|
||||
|
||||
if (points % nextLevelPoints == 0) {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawLevelText() {
|
||||
g.setColor("#26b6c7");
|
||||
g.setFontAlign(0, 0);
|
||||
g.setFont("4x6", 5);
|
||||
g.drawString("Level " + level, 120, 80);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
//bg
|
||||
g.setColor("#71c6cf");
|
||||
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||
|
||||
//counter
|
||||
drawCounter();
|
||||
|
||||
//draw level
|
||||
drawLevelText();
|
||||
|
||||
//dot
|
||||
g.setColor("#ff0000");
|
||||
g.fillCircle(dotx, doty, dotwidth);
|
||||
|
||||
//ball
|
||||
g.drawImage(BALL, ballx, bally);
|
||||
|
||||
g.flip();
|
||||
}
|
||||
|
||||
function drawCounter() {
|
||||
g.setColor("#000000");
|
||||
g.fillRect(g.getWidth() - counterWidth, 0, g.getWidth(), gHeight);
|
||||
|
||||
if(counter < 40 ) g.setColor("#fc0303");
|
||||
else if (counter < 80 ) g.setColor("#fc9803");
|
||||
else g.setColor("#0318fc");
|
||||
|
||||
g.fillRect(
|
||||
g.getWidth() - counterWidth,
|
||||
gHeight,
|
||||
g.getWidth(),
|
||||
gHeight - counter
|
||||
);
|
||||
}
|
||||
|
||||
function checkCollision() {
|
||||
if (ballx < 0) {
|
||||
ballx = 0;
|
||||
if (!xBuzzed) collide();
|
||||
xBuzzed = true;
|
||||
} else if (ballx > gWidth - ballDims) {
|
||||
ballx = gWidth - ballDims;
|
||||
if (!xBuzzed) collide();
|
||||
xBuzzed = true;
|
||||
} else {
|
||||
xBuzzed = false;
|
||||
}
|
||||
|
||||
if (bally < 0) {
|
||||
bally = 0;
|
||||
if (!yBuzzed) collide();
|
||||
yBuzzed = true;
|
||||
} else if (bally > gHeight - ballDims) {
|
||||
bally = gHeight - ballDims;
|
||||
if (!yBuzzed) collide();
|
||||
yBuzzed = true;
|
||||
} else {
|
||||
yBuzzed = false;
|
||||
}
|
||||
}
|
||||
|
||||
function count() {
|
||||
counter -= levelSpeedStart + level * levelSpeedFactor;
|
||||
if (counter <= 0) {
|
||||
running = false;
|
||||
clearInterval(drawInterval);
|
||||
setTimeout(function(){ E.showMessage("Press Button 1\nto restart.", "Gameover!");},50);
|
||||
}
|
||||
}
|
||||
|
||||
function accel(values) {
|
||||
ballx -= values.x * ballSpeedFactor;
|
||||
bally -= values.y * ballSpeedFactor;
|
||||
}
|
||||
|
||||
function play() {
|
||||
if (running) {
|
||||
accel(Bangle.getAccel());
|
||||
checkCollision();
|
||||
checkIfDotEaten();
|
||||
count();
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
reset();
|
||||
drawInterval = setInterval(play, redrawspeed);
|
||||
|
||||
setWatch(
|
||||
() => {
|
||||
if(!running) reset();
|
||||
},
|
||||
BTN1,
|
||||
{ repeat: true }
|
||||
);
|
||||
|
||||
running = true;
|
||||
}, 10);
|
After Width: | Height: | Size: 14 KiB |
|
@ -2,3 +2,6 @@
|
|||
0.02: Increase contrast (darker notification background, white text)
|
||||
0.03: Gadgetbridge widget now shows connection state
|
||||
0.04: Tweaks for variable size widget system
|
||||
0.05: Show incoming call notification
|
||||
Optimize animation, limit title length
|
||||
0.06: Gadgetbridge App 'Connected' state is no longer toggleable
|
||||
|
|
|
@ -4,7 +4,7 @@ function gb(j) {
|
|||
|
||||
var mainmenu = {
|
||||
"" : { "title" : "Gadgetbridge" },
|
||||
"Connected" : { value : NRF.getSecurityStatus().connected },
|
||||
"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" },
|
||||
"Find Phone" : function() { E.showMenu(findPhone); },
|
||||
"Exit" : ()=> {load();},
|
||||
};
|
||||
|
|
|
@ -1,125 +1,196 @@
|
|||
(function() {
|
||||
var musicState = "stop";
|
||||
var musicInfo = {"artist":"","album":"","track":""};
|
||||
var scrollPos = 0;
|
||||
function gb(j) {
|
||||
Bluetooth.println(JSON.stringify(j));
|
||||
(() => {
|
||||
|
||||
const state = {
|
||||
music: "stop",
|
||||
|
||||
musicInfo: {
|
||||
artist: "",
|
||||
album: "",
|
||||
track: ""
|
||||
},
|
||||
|
||||
scrollPos: 0
|
||||
};
|
||||
|
||||
function gbSend(message) {
|
||||
Bluetooth.println(JSON.stringify(message));
|
||||
}
|
||||
function show(size,render) {
|
||||
|
||||
function showNotification(size, render) {
|
||||
var oldMode = Bangle.getLCDMode();
|
||||
|
||||
Bangle.setLCDMode("direct");
|
||||
g.setClipRect(0,240,239,319);
|
||||
g.setClipRect(0, 240, 239, 319);
|
||||
g.setColor("#222222");
|
||||
g.fillRect(1,241,238,318);
|
||||
render(320-size);
|
||||
g.fillRect(1, 241, 238, 318);
|
||||
|
||||
render(320 - size);
|
||||
|
||||
g.setColor("#ffffff");
|
||||
g.fillRect(0,240,1,319);
|
||||
g.fillRect(238,240,239,319);
|
||||
g.fillRect(2,318,238,319);
|
||||
g.fillRect(0, 240, 1, 319);
|
||||
g.fillRect(238, 240, 239, 319);
|
||||
g.fillRect(2, 318, 238, 319);
|
||||
|
||||
Bangle.setLCDPower(1); // light up
|
||||
Bangle.setLCDMode(oldMode); // clears cliprect
|
||||
|
||||
function anim() {
|
||||
scrollPos-=2;
|
||||
if (scrollPos<-size) scrollPos=-size;
|
||||
Bangle.setLCDOffset(scrollPos);
|
||||
if (scrollPos>-size) setTimeout(anim,10);
|
||||
}
|
||||
anim();
|
||||
}
|
||||
function hide() {
|
||||
function anim() {
|
||||
scrollPos+=4;
|
||||
if (scrollPos>0) scrollPos=0;
|
||||
Bangle.setLCDOffset(scrollPos);
|
||||
if (scrollPos<0) setTimeout(anim,10);
|
||||
state.scrollPos -= 2;
|
||||
if (state.scrollPos < -size) {
|
||||
state.scrollPos = -size;
|
||||
}
|
||||
Bangle.setLCDOffset(state.scrollPos);
|
||||
if (state.scrollPos > -size) setTimeout(anim, 15);
|
||||
}
|
||||
anim();
|
||||
}
|
||||
|
||||
Bangle.on('touch',function() {
|
||||
if (scrollPos) hide();
|
||||
});
|
||||
Bangle.on('swipe',function(dir) {
|
||||
if (musicState=="play") {
|
||||
gb({t:"music",n:dir>0?"next":"previous"});
|
||||
function hideNotification() {
|
||||
function anim() {
|
||||
state.scrollPos += 4;
|
||||
if (state.scrollPos > 0) state.scrollPos = 0;
|
||||
Bangle.setLCDOffset(state.scrollPos);
|
||||
if (state.scrollPos < 0) setTimeout(anim, 10);
|
||||
}
|
||||
});
|
||||
gb({t:"status",bat:E.getBattery()});
|
||||
anim();
|
||||
}
|
||||
|
||||
global.GB = function(j) {
|
||||
switch (j.t) {
|
||||
function handleNotificationEvent(event) {
|
||||
|
||||
// split text up at word boundaries
|
||||
var txt = event.body.split("\n");
|
||||
var MAXCHARS = 38;
|
||||
for (var i = 0; i < txt.length; i++) {
|
||||
txt[i] = txt[i].trim();
|
||||
var l = txt[i];
|
||||
if (l.length > MAXCHARS) {
|
||||
var p = MAXCHARS;
|
||||
while (p > MAXCHARS - 8 && !" \t-_".includes(l[p]))
|
||||
p--;
|
||||
if (p == MAXCHARS - 8) p = MAXCHARS;
|
||||
txt[i] = l.substr(0, p);
|
||||
txt.splice(i + 1, 0, l.substr(p));
|
||||
}
|
||||
}
|
||||
|
||||
showNotification(80, (y) => {
|
||||
|
||||
// TODO: icon based on src?
|
||||
var x = 120;
|
||||
g.setFontAlign(0, 0);
|
||||
g.setFont("6x8", 1);
|
||||
g.setColor("#40d040");
|
||||
g.drawString(event.src, x, y + 7);
|
||||
|
||||
g.setColor("#ffffff");
|
||||
g.setFont("6x8", 2);
|
||||
if (event.title)
|
||||
g.drawString(event.title.slice(0,17), x, y + 25);
|
||||
|
||||
g.setFont("6x8", 1);
|
||||
g.setColor("#ffffff");
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(txt.join("\n"), 10, y + 40);
|
||||
});
|
||||
|
||||
Bangle.buzz();
|
||||
}
|
||||
|
||||
function handleMusicStateUpdate(event) {
|
||||
state.music = event.state
|
||||
|
||||
if (state.music == "play") {
|
||||
showNotification(40, (y) => {
|
||||
g.setColor("#ffffff");
|
||||
g.drawImage(require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")), 8, y + 8);
|
||||
|
||||
g.setFontAlign(-1, -1);
|
||||
var x = 40;
|
||||
g.setFont("4x6", 2);
|
||||
g.setColor("#ffffff");
|
||||
g.drawString(state.musicInfo.artist, x, y + 8);
|
||||
|
||||
g.setFont("6x8", 1);
|
||||
g.setColor("#ffffff");
|
||||
g.drawString(state.musicInfo.track, x, y + 22);
|
||||
});
|
||||
}
|
||||
|
||||
if (state.music == "pause") {
|
||||
hideNotification();
|
||||
}
|
||||
}
|
||||
|
||||
function handleCallEvent(event) {
|
||||
|
||||
if (event.cmd == "accept") {
|
||||
showNotification(40, (y) => {
|
||||
g.setColor("#ffffff");
|
||||
g.drawImage(require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw=")), 8, y + 8);
|
||||
|
||||
g.setFontAlign(-1, -1);
|
||||
var x = 40;
|
||||
g.setFont("4x6", 2);
|
||||
g.setColor("#ffffff");
|
||||
g.drawString(event.name, x, y + 8);
|
||||
|
||||
g.setFont("6x8", 1);
|
||||
g.setColor("#ffffff");
|
||||
g.drawString(event.number, x, y + 22);
|
||||
});
|
||||
|
||||
Bangle.buzz();
|
||||
}
|
||||
}
|
||||
|
||||
global.GB = (event) => {
|
||||
switch (event.t) {
|
||||
case "notify":
|
||||
show(80,function(y) {
|
||||
// TODO: icon based on src?
|
||||
var x = 120;
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont("6x8",1);
|
||||
g.setColor("#40d040");
|
||||
g.drawString(j.src,x,y+7);
|
||||
g.setColor("#ffffff");
|
||||
g.setFont("6x8",2);
|
||||
g.drawString(j.title,x,y+25);
|
||||
g.setFont("6x8",1);
|
||||
g.setColor("#ffffff");
|
||||
// split text up a word boundaries
|
||||
var txt = j.body.split("\n");
|
||||
var MAXCHARS = 38;
|
||||
for (var i=0;i<txt.length;i++) {
|
||||
txt[i] = txt[i].trim();
|
||||
var l = txt[i];
|
||||
if (l.length>MAXCHARS) {
|
||||
var p = MAXCHARS;
|
||||
while (p>MAXCHARS-8 && !" \t-_".includes(l[p]))
|
||||
p--;
|
||||
if (p==MAXCHARS-8) p=MAXCHARS;
|
||||
txt[i] = l.substr(0,p);
|
||||
txt.splice(i+1,0,l.substr(p));
|
||||
}
|
||||
}
|
||||
g.setFontAlign(-1,-1);
|
||||
g.drawString(txt.join("\n"),10,y+40);
|
||||
Bangle.buzz();
|
||||
});
|
||||
break;
|
||||
handleNotificationEvent(event);
|
||||
break;
|
||||
case "musicinfo":
|
||||
musicInfo = j;
|
||||
state.musicInfo = event;
|
||||
break;
|
||||
case "musicstate":
|
||||
musicState = j.state;
|
||||
if (musicState=="play")
|
||||
show(40,function(y) {
|
||||
g.setColor("#ffffff");
|
||||
g.drawImage( require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")),8,y+8);
|
||||
g.setFontAlign(-1,-1);
|
||||
g.setFont("6x8",1);
|
||||
var x = 40;
|
||||
g.setFont("4x6",2);
|
||||
g.setColor("#ffffff");
|
||||
g.drawString(musicInfo.artist,x,y+8);
|
||||
g.setFont("6x8",1);
|
||||
g.setColor("#ffffff");
|
||||
g.drawString(musicInfo.track,x,y+22);
|
||||
});
|
||||
if (musicState=="pause")
|
||||
hide();
|
||||
break;
|
||||
handleMusicStateUpdate(event);
|
||||
break;
|
||||
case "call":
|
||||
handleCallEvent(event);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
function draw() {
|
||||
g.setColor(-1);
|
||||
if (NRF.getSecurityStatus().connected)
|
||||
g.drawImage(require("heatshrink").decompress(atob("i0WwgHExAABCIwJCBYwJEBYkIBQ2ACgvzCwoECx/z/AKDD4WD+YLBEIYKCx//+cvnAKCBwU/mc4/8/HYv//Ev+Y4EEAePn43DBQkzn4rCEIoABBIwKHO4cjmczK42I6mqlqEEBQeIBQaDED4IgDUhi6KaBbmIA==")),this.x+1,this.y+1);
|
||||
else
|
||||
g.drawImage(require("heatshrink").decompress(atob("i0WwQFC1WgAgYFDAgIFClQFCwEK1W/AoIPB1f+CAMq1f7/WqwQPB/fq1Gq1/+/4dC/2/CAIaB/YbBAAO///qAoX/B4QbBDQQ7BDQQrBAAWoIIIACIIIVC0ECB4cACAZiBAoRtCAoIDBA")),this.x+1,this.y+1);
|
||||
}
|
||||
function changed() {
|
||||
WIDGETS["gbridgew"].draw();
|
||||
g.flip();// turns screen on
|
||||
}
|
||||
NRF.on('connected',changed);
|
||||
NRF.on('disconnected',changed);
|
||||
// Touch control
|
||||
Bangle.on("touch", () => {
|
||||
if (state.scrollPos) {
|
||||
hideNotification();
|
||||
}
|
||||
});
|
||||
|
||||
WIDGETS["gbridgew"]={area:"tl",width:24,draw:draw};
|
||||
Bangle.on("swipe", (dir) => {
|
||||
if (state.music == "play") {
|
||||
const command = dir > 0 ? "next" : "previous"
|
||||
gbSend({ t: "music", n: command });
|
||||
}
|
||||
});
|
||||
|
||||
function draw() {
|
||||
g.setColor(-1);
|
||||
if (NRF.getSecurityStatus().connected)
|
||||
g.drawImage(require("heatshrink").decompress(atob("i0WwgHExAABCIwJCBYwJEBYkIBQ2ACgvzCwoECx/z/AKDD4WD+YLBEIYKCx//+cvnAKCBwU/mc4/8/HYv//Ev+Y4EEAePn43DBQkzn4rCEIoABBIwKHO4cjmczK42I6mqlqEEBQeIBQaDED4IgDUhi6KaBbmIA==")), this.x + 1, this.y + 1);
|
||||
else
|
||||
g.drawImage(require("heatshrink").decompress(atob("i0WwQFC1WgAgYFDAgIFClQFCwEK1W/AoIPB1f+CAMq1f7/WqwQPB/fq1Gq1/+/4dC/2/CAIaB/YbBAAO///qAoX/B4QbBDQQ7BDQQrBAAWoIIIACIIIVC0ECB4cACAZiBAoRtCAoIDBA")), this.x + 1, this.y + 1);
|
||||
}
|
||||
|
||||
function changedConnectionState() {
|
||||
WIDGETS["gbridgew"].draw();
|
||||
g.flip(); // turns screen on
|
||||
}
|
||||
|
||||
NRF.on("connected", changedConnectionState);
|
||||
NRF.on("disconnected", changedConnectionState);
|
||||
|
||||
WIDGETS["gbridgew"] = { area: "tl", width: 24, draw: draw };
|
||||
|
||||
gbSend({ t: "status", bat: E.getBattery() });
|
||||
})();
|
||||
|
|
|
@ -11,17 +11,7 @@ var domRecords = document.getElementById("records");
|
|||
|
||||
function saveRecord(record,name) {
|
||||
var csv = `${record.map(rec=>[rec.time, rec.bpm, rec.confidence].join(",")).join("\n")}`;
|
||||
var a = document.createElement("a"),
|
||||
file = new Blob([csv], {type: "Comma-separated value file"});
|
||||
var url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = name+".csv";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function() {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
Util.saveCSV(name, csv);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,14 @@ exports = { name : "en_GB", currencySym:"£",
|
|||
});
|
||||
|
||||
var languageSelector = document.getElementById("languages");
|
||||
languageSelector.innerHTML = Object.keys(locales).map(l=>`<option value="${l}">${l}</option>`).join("\n");
|
||||
languageSelector.innerHTML = Object.keys(locales).map(l=>{
|
||||
var localeParts = l.split("_"); // en_GB -> ["en","GB"]
|
||||
var icon = "";
|
||||
// If we have a 2 char ISO country code, use it to get the unicode flag
|
||||
if (localeParts[1] && localeParts[1].length==2)
|
||||
icon = localeParts[1].toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0)+127397) )+" ";
|
||||
return `<option value="${l}">${icon}${l}</option>`
|
||||
}).join("\n");
|
||||
|
||||
document.getElementById("upload").addEventListener("click", function() {
|
||||
|
||||
|
|
|
@ -370,4 +370,21 @@ var locales = {
|
|||
abday: "Vas,Hét,Ke,Szer,Csüt,Pén,Szom",
|
||||
day: "Vasárnap,Hétfő,Kedd,Szerda,Csütörtök,Péntek,Szombat",
|
||||
trans: { yes: "igen", Yes: "Igen", no: "nem", No: "Nem", ok: "ok", on: "be", off: "ki" }},
|
||||
"pt_BR": {
|
||||
lang: "pt_BR",
|
||||
decimal_point: ",",
|
||||
thousands_sep: ".",
|
||||
currency_symbol: "R$", currency_first:true,
|
||||
int_curr_symbol: "BRL",
|
||||
speed: "kmh",
|
||||
distance: { 0: "m", 1: "km" },
|
||||
temperature: "°C",
|
||||
ampm: {0:"am",1:"pm"},
|
||||
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "", 1: "%d/%m/%y" },
|
||||
abmonth: "Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez",
|
||||
month: "Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro",
|
||||
abday: "Dom,Seg,Ter,Qua,Qui,Sex,Sab",
|
||||
day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado",
|
||||
trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" }},
|
||||
};
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
0.02: Fix day of the week and add padding
|
||||
0.03: use short date format from locale, take timeout from settings
|
||||
0.04: modify date to display to be more at the original idea but still localized
|
||||
0.05: use 12/24 hour clock from settings
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
/**********************************
|
||||
BangleJS MARIO CLOCK V0.1.0
|
||||
BangleJS MARIO CLOCK
|
||||
+ Based on Espruino Mario Clock V3 https://github.com/paulcockrell/espruino-mario-clock
|
||||
+ Converting images to 1bit BMP: Image > Mode > Indexed and tick the "Use black and white (1-bit) palette", Then export as BMP.
|
||||
+ Online Image convertor: https://www.espruino.com/Image+Converter
|
||||
**********************************/
|
||||
|
||||
var locale = require("locale");
|
||||
const locale = require("locale");
|
||||
const storage = require('Storage');
|
||||
const settings = (storage.readJSON('setting.json',1)||{});
|
||||
const timeout = settings.timeout||10;
|
||||
const settings = (storage.readJSON('setting.json', 1) || {});
|
||||
const timeout = settings.timeout || 10;
|
||||
const is12Hour = settings["12hour"] || false;
|
||||
|
||||
// Screen dimensions
|
||||
let W, H;
|
||||
|
@ -273,7 +274,8 @@ function drawTime() {
|
|||
drawBrick(42, 25);
|
||||
|
||||
const t = new Date();
|
||||
const hours = ("0" + t.getHours()).substr(-2);
|
||||
const h = t.getHours();
|
||||
const hours = ("0" + ((is12Hour && h > 12) ? h - 12 : h)).substr(-2);
|
||||
const mins = ("0" + t.getMinutes()).substr(-2);
|
||||
|
||||
g.setFont("6x8");
|
||||
|
@ -374,8 +376,9 @@ function init() {
|
|||
Bangle.setLCDPower(true);
|
||||
}
|
||||
});
|
||||
|
||||
startTimers();
|
||||
}
|
||||
|
||||
// Initialise!
|
||||
init();
|
||||
startTimers();
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Added GPS to obtain coordinates, added buttons
|
|
@ -1,218 +1,215 @@
|
|||
//Icons from https://icons8.com
|
||||
//Sun and Moon calculations from https://github.com/mourner/suncalc and https://gist.github.com/endel/dfe6bb2fbe679781948c
|
||||
|
||||
//varibales
|
||||
const storage = require('Storage');
|
||||
let coords;
|
||||
var timer;
|
||||
var fix;
|
||||
|
||||
var PI = Math.PI,
|
||||
sin = Math.sin,
|
||||
cos = Math.cos,
|
||||
tan = Math.tan,
|
||||
asin = Math.asin,
|
||||
atan = Math.atan2,
|
||||
acos = Math.acos,
|
||||
rad = PI / 180,
|
||||
dayMs = 1000 * 60 * 60 * 24,
|
||||
J1970 = 2440588,
|
||||
J2000 = 2451545;
|
||||
|
||||
var SunCalc = {};
|
||||
|
||||
//pictures
|
||||
function getImg(i) {
|
||||
var data = {
|
||||
"NewMoon": "AD8AAH/4AHwPgDwA8BwADg4AAcMAADHAAA5gAAGYAABsAAAPAAADwAAA8AAAPAAADwAAA2AAAZgAAGcAADjAAAw4AAcHAAOA8APAHwPgAf/gAA/AAA==",
|
||||
"WaxingCrescentNorth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==",
|
||||
"WaningCrescentSouth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==",
|
||||
"FirstQuarterNorth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==",
|
||||
"FirstQuarterSouth" : "AD8AAH/4AH+PgD/g8B/4Dg/+AcP/gDH/4A5/+AGf/gBv/4AP/+AD//gA//4AP/+AD//gA3/4AZ/+AGf/gDj/4Aw/+AcH/gOA/4PAH+PgAf/gAA/AAA==",
|
||||
"WaxingGibbousNorth" : "AD8AAH/4AH3/gDz/8Bw//g4f/8MH//HB//5g//+YP//sD///A///wP//8D///A///wP//2D//5g//+cH//jB//w4f/8HD/+A8//AH3/gAf/gAA/AAA==",
|
||||
"WaxingGibbousSouth" : "AD8AAH/4AH/vgD/88B//Dg//4cP/+DH//g5//8Gf//Bv//wP//8D///A///wP//8D///A3//wZ//8Gf/+Dj//gw//4cH/8OA//PAH/vgAf/gAA/AAA==",
|
||||
"FullMoon" : "AD8AAH/4AH//gD//8B///g///8P///H///5///+f///v/////////////////////////3///5///+f///j///w///8H//+A///AH//gAf/gAA/AAA==",
|
||||
"WaningGibbousNorth" : "AD8AAH/4AH/vgD/88B//Dg//4cP/+DH//g5//8Gf//Bv//wP//8D///A///wP//8D///A3//wZ//8Gf/+Dj//gw//4cH/8OA//PAH/vgAf/gAA/AAA==",
|
||||
"WaningGibbousSouth" : "AD8AAH/4AH3/gDz/8Bw//g4f/8MH//HB//5g//+YP//sD///A///wP//8D///A///wP//2D//5g//+cH//jB//w4f/8HD/+A8//AH3/gAf/gAA/AAA==",
|
||||
"LastQuarterNorth" : "AD8AAH/4AH+PgD/g8B/4Dg/+AcP/gDH/4A5/+AGf/gBv/4AP/+AD//gA//4AP/+AD//gA3/4AZ/+AGf/gDj/4Aw/+AcH/gOA/4PAH+PgAf/gAA/AAA==",
|
||||
"LastQuarterSouth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==",
|
||||
"WaningCrescentNorth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==",
|
||||
"WaxingCrescentSouth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA=="
|
||||
};
|
||||
return {
|
||||
width : 26, height : 26, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : E.toArrayBuffer(atob(data[i]))
|
||||
};
|
||||
var data = {
|
||||
"NewMoon": "AD8AAH/4AHwPgDwA8BwADg4AAcMAADHAAA5gAAGYAABsAAAPAAADwAAA8AAAPAAADwAAA2AAAZgAAGcAADjAAAw4AAcHAAOA8APAHwPgAf/gAA/AAA==",
|
||||
"WaxingCrescentNorth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==",
|
||||
"WaningCrescentSouth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==",
|
||||
"FirstQuarterNorth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==",
|
||||
"FirstQuarterSouth" : "AD8AAH/4AH+PgD/g8B/4Dg/+AcP/gDH/4A5/+AGf/gBv/4AP/+AD//gA//4AP/+AD//gA3/4AZ/+AGf/gDj/4Aw/+AcH/gOA/4PAH+PgAf/gAA/AAA==",
|
||||
"WaxingGibbousNorth" : "AD8AAH/4AH3/gDz/8Bw//g4f/8MH//HB//5g//+YP//sD///A///wP//8D///A///wP//2D//5g//+cH//jB//w4f/8HD/+A8//AH3/gAf/gAA/AAA==",
|
||||
"WaxingGibbousSouth" : "AD8AAH/4AH/vgD/88B//Dg//4cP/+DH//g5//8Gf//Bv//wP//8D///A///wP//8D///A3//wZ//8Gf/+Dj//gw//4cH/8OA//PAH/vgAf/gAA/AAA==",
|
||||
"FullMoon" : "AD8AAH/4AH//gD//8B///g///8P///H///5///+f///v/////////////////////////3///5///+f///j///w///8H//+A///AH//gAf/gAA/AAA==",
|
||||
"WaningGibbousNorth" : "AD8AAH/4AH/vgD/88B//Dg//4cP/+DH//g5//8Gf//Bv//wP//8D///A///wP//8D///A3//wZ//8Gf/+Dj//gw//4cH/8OA//PAH/vgAf/gAA/AAA==",
|
||||
"WaningGibbousSouth" : "AD8AAH/4AH3/gDz/8Bw//g4f/8MH//HB//5g//+YP//sD///A///wP//8D///A///wP//2D//5g//+cH//jB//w4f/8HD/+A8//AH3/gAf/gAA/AAA==",
|
||||
"LastQuarterNorth" : "AD8AAH/4AH+PgD/g8B/4Dg/+AcP/gDH/4A5/+AGf/gBv/4AP/+AD//gA//4AP/+AD//gA3/4AZ/+AGf/gDj/4Aw/+AcH/gOA/4PAH+PgAf/gAA/AAA==",
|
||||
"LastQuarterSouth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==",
|
||||
"WaningCrescentNorth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==",
|
||||
"WaxingCrescentSouth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA=="
|
||||
};
|
||||
return {
|
||||
width : 26, height : 26, bpp : 1,
|
||||
transparent : 0,
|
||||
buffer : E.toArrayBuffer(atob(data[i]))
|
||||
};
|
||||
}
|
||||
|
||||
//coordinates (will get from GPS later on real device)
|
||||
var lat = 52.96236,
|
||||
lon = 7.62571;
|
||||
|
||||
var PI = Math.PI,
|
||||
sin = Math.sin,
|
||||
cos = Math.cos,
|
||||
tan = Math.tan,
|
||||
asin = Math.asin,
|
||||
atan = Math.atan2,
|
||||
acos = Math.acos,
|
||||
rad = PI / 180;
|
||||
|
||||
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
|
||||
// date/time constants and conversions
|
||||
var dayMs = 1000 * 60 * 60 * 24,
|
||||
J1970 = 2440588,
|
||||
J2000 = 2451545;
|
||||
|
||||
function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
|
||||
function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); }
|
||||
function toDays(date) { return toJulian(date) - J2000; }
|
||||
|
||||
// general calculations for position
|
||||
var e = rad * 23.4397; // obliquity of the Earth
|
||||
function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
|
||||
function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
|
||||
function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
|
||||
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
|
||||
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
|
||||
function astroRefraction(h) {
|
||||
if (h < 0) // the following formula works for positive altitudes only.
|
||||
h = 0; // if h = -0.08901179 a div/0 would occur.
|
||||
|
||||
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
|
||||
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
|
||||
}
|
||||
|
||||
// general sun calculations
|
||||
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
|
||||
function eclipticLongitude(M) {
|
||||
|
||||
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
|
||||
P = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return M + C + P + PI;
|
||||
}
|
||||
|
||||
function sunCoords(d) {
|
||||
|
||||
var M = solarMeanAnomaly(d),
|
||||
L = eclipticLongitude(M);
|
||||
|
||||
return {
|
||||
dec: declination(L, 0),
|
||||
ra: rightAscension(L, 0)
|
||||
};
|
||||
}
|
||||
|
||||
var SunCalc = {};
|
||||
|
||||
// adds a custom time to the times config
|
||||
SunCalc.addTime = function (angle, riseName, setName) {
|
||||
times.push([angle, riseName, setName]);
|
||||
};
|
||||
|
||||
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
|
||||
function moonCoords(d) { // geocentric ecliptic coordinates of the moon
|
||||
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
|
||||
M = rad * (134.963 + 13.064993 * d), // mean anomaly
|
||||
F = rad * (93.272 + 13.229350 * d), // mean distance
|
||||
l = L + rad * 6.289 * sin(M), // longitude
|
||||
b = rad * 5.128 * sin(F), // latitude
|
||||
dt = 385001 - 20905 * cos(M); // distance to the moon in km
|
||||
|
||||
return {
|
||||
ra: rightAscension(l, b),
|
||||
dec: declination(l, b),
|
||||
dist: dt
|
||||
};
|
||||
}
|
||||
|
||||
SunCalc.getMoonPosition = function (date, lat, lng) {
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
d = toDays(date),
|
||||
c = moonCoords(d),
|
||||
H = siderealTime(d, lw) - c.ra,
|
||||
h = altitude(H, phi, c.dec),
|
||||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
|
||||
h = h + astroRefraction(h); // altitude correction for refraction
|
||||
return {
|
||||
azimuth: azimuth(H, phi, c.dec),
|
||||
altitude: h,
|
||||
distance: c.dist,
|
||||
parallacticAngle: pa
|
||||
};
|
||||
};
|
||||
|
||||
// calculations for illumination parameters of the moon,
|
||||
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
|
||||
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
|
||||
SunCalc.getMoonIllumination = function (date) {
|
||||
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
|
||||
// date/time constants and conversions
|
||||
function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
|
||||
function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); }
|
||||
function toDays(date) { return toJulian(date) - J2000; }
|
||||
|
||||
// general calculations for position
|
||||
var e = rad * 23.4397; // obliquity of the Earth
|
||||
function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
|
||||
function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
|
||||
function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
|
||||
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
|
||||
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
|
||||
function astroRefraction(h) {
|
||||
if (h < 0) // the following formula works for positive altitudes only.
|
||||
h = 0; // if h = -0.08901179 a div/0 would occur.
|
||||
|
||||
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
|
||||
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
|
||||
}
|
||||
|
||||
// general sun calculations
|
||||
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
|
||||
function eclipticLongitude(M) {
|
||||
|
||||
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
|
||||
P = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return M + C + P + PI;
|
||||
}
|
||||
|
||||
function sunCoords(d) {
|
||||
var M = solarMeanAnomaly(d),
|
||||
L = eclipticLongitude(M);
|
||||
return {
|
||||
dec: declination(L, 0),
|
||||
ra: rightAscension(L, 0)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// adds a custom time to the times config
|
||||
SunCalc.addTime = function (angle, riseName, setName) {
|
||||
times.push([angle, riseName, setName]);
|
||||
};
|
||||
|
||||
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
|
||||
function moonCoords(d) { // geocentric ecliptic coordinates of the moon
|
||||
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
|
||||
M = rad * (134.963 + 13.064993 * d), // mean anomaly
|
||||
F = rad * (93.272 + 13.229350 * d), // mean distance
|
||||
l = L + rad * 6.289 * sin(M), // longitude
|
||||
b = rad * 5.128 * sin(F), // latitude
|
||||
dt = 385001 - 20905 * cos(M); // distance to the moon in km
|
||||
|
||||
return {
|
||||
ra: rightAscension(l, b),
|
||||
dec: declination(l, b),
|
||||
dist: dt
|
||||
};
|
||||
}
|
||||
|
||||
SunCalc.getMoonPosition = function (date, lat, lng) {
|
||||
|
||||
var lw = rad * -lng,
|
||||
phi = rad * lat,
|
||||
d = toDays(date),
|
||||
c = moonCoords(d),
|
||||
H = siderealTime(d, lw) - c.ra,
|
||||
h = altitude(H, phi, c.dec),
|
||||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
|
||||
h = h + astroRefraction(h); // altitude correction for refraction
|
||||
return {
|
||||
azimuth: azimuth(H, phi, c.dec),
|
||||
altitude: h,
|
||||
distance: c.dist,
|
||||
parallacticAngle: pa
|
||||
};
|
||||
};
|
||||
|
||||
// calculations for illumination parameters of the moon,
|
||||
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
|
||||
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
SunCalc.getMoonIllumination = function (date) {
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth();
|
||||
var day = date.getDate();
|
||||
var Moon = {
|
||||
phases: ['new', 'waxing-crescent', 'first-quarter', 'waxing-gibbous', 'full', 'waning-gibbous', 'last-quarter', 'waning-crescent'],
|
||||
phase: function (year, month, day) {
|
||||
let c = 0;
|
||||
let e = 0;
|
||||
let jd = 0;
|
||||
let b = 0;
|
||||
if (month < 3) {
|
||||
year--;
|
||||
month += 12;
|
||||
}
|
||||
++month;
|
||||
c = 365.25 * year;
|
||||
e = 30.6 * month;
|
||||
jd = c + e + day - 694039.09; // jd is total days elapsed
|
||||
jd /= 29.5305882; // divide by the moon cycle
|
||||
b = parseInt(jd); // int(jd) -> b, take integer part of jd
|
||||
jd -= b; // subtract integer part to leave fractional part of original jd
|
||||
b = Math.round(jd * 8); // scale fraction from 0-8 and round
|
||||
if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0
|
||||
//print ({phase: b, name: Moon.phases[b]});
|
||||
return {phase: b, name: Moon.phases[b]};
|
||||
phases: ['new', 'waxing-crescent', 'first-quarter', 'waxing-gibbous', 'full', 'waning-gibbous', 'last-quarter', 'waning-crescent'],
|
||||
phase: function (year, month, day) {
|
||||
let c = 0;
|
||||
let e = 0;
|
||||
let jd = 0;
|
||||
let b = 0;
|
||||
if (month < 3) {
|
||||
year--;
|
||||
month += 12;
|
||||
}
|
||||
++month;
|
||||
c = 365.25 * year;
|
||||
e = 30.6 * month;
|
||||
jd = c + e + day - 694039.09; // jd is total days elapsed
|
||||
jd /= 29.5305882; // divide by the moon cycle
|
||||
b = parseInt(jd); // int(jd) -> b, take integer part of jd
|
||||
jd -= b; // subtract integer part to leave fractional part of original jd
|
||||
b = Math.round(jd * 8); // scale fraction from 0-8 and round
|
||||
if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0
|
||||
return {phase: b, name: Moon.phases[b]};
|
||||
}
|
||||
};
|
||||
return (Moon.phase(year, month, day));
|
||||
};
|
||||
|
||||
function hoursLater(date, h) {
|
||||
return new Date(date.valueOf() + h * dayMs / 24);
|
||||
}
|
||||
|
||||
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
|
||||
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
|
||||
var t = new Date(date);
|
||||
if (inUTC) t.setUTCHours(0, 0, 0, 0);
|
||||
else t.setHours(0, 0, 0, 0);
|
||||
var hc = 0.133 * rad,
|
||||
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
|
||||
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
|
||||
|
||||
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
|
||||
for (var i = 1; i <= 24; i += 2) {
|
||||
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
|
||||
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
|
||||
a = (h0 + h2) / 2 - h1;
|
||||
b = (h2 - h0) / 2;
|
||||
xe = -b / (2 * a);
|
||||
ye = (a * xe + b) * xe + h1;
|
||||
d = b * b - 4 * a * h1;
|
||||
roots = 0;
|
||||
if (d >= 0) {
|
||||
dx = Math.sqrt(d) / (Math.abs(a) * 2);
|
||||
x1 = xe - dx;
|
||||
x2 = xe + dx;
|
||||
if (Math.abs(x1) <= 1) roots++;
|
||||
if (Math.abs(x2) <= 1) roots++;
|
||||
if (x1 < -1) x1 = x2;
|
||||
}
|
||||
if (roots === 1) {
|
||||
if (h0 < 0) rise = i + x1;
|
||||
else set = i + x1;
|
||||
} else if (roots === 2) {
|
||||
rise = i + (ye < 0 ? x2 : x1);
|
||||
set = i + (ye < 0 ? x1 : x2);
|
||||
}
|
||||
if (rise && set) break;
|
||||
h0 = h2;
|
||||
}
|
||||
};
|
||||
return (Moon.phase(year, month, day));
|
||||
};
|
||||
|
||||
function hoursLater(date, h) {
|
||||
return new Date(date.valueOf() + h * dayMs / 24);
|
||||
}
|
||||
|
||||
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
|
||||
|
||||
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
|
||||
var t = new Date(date);
|
||||
if (inUTC) t.setUTCHours(0, 0, 0, 0);
|
||||
else t.setHours(0, 0, 0, 0);
|
||||
var hc = 0.133 * rad,
|
||||
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
|
||||
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
|
||||
|
||||
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
|
||||
for (var i = 1; i <= 24; i += 2) {
|
||||
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
|
||||
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
|
||||
a = (h0 + h2) / 2 - h1;
|
||||
b = (h2 - h0) / 2;
|
||||
xe = -b / (2 * a);
|
||||
ye = (a * xe + b) * xe + h1;
|
||||
d = b * b - 4 * a * h1;
|
||||
roots = 0;
|
||||
if (d >= 0) {
|
||||
dx = Math.sqrt(d) / (Math.abs(a) * 2);
|
||||
x1 = xe - dx;
|
||||
x2 = xe + dx;
|
||||
if (Math.abs(x1) <= 1) roots++;
|
||||
if (Math.abs(x2) <= 1) roots++;
|
||||
if (x1 < -1) x1 = x2;
|
||||
}
|
||||
if (roots === 1) {
|
||||
if (h0 < 0) rise = i + x1;
|
||||
else set = i + x1;
|
||||
} else if (roots === 2) {
|
||||
rise = i + (ye < 0 ? x2 : x1);
|
||||
set = i + (ye < 0 ? x1 : x2);
|
||||
}
|
||||
if (rise && set) break;
|
||||
h0 = h2;
|
||||
}
|
||||
var result = {};
|
||||
if (rise) result.rise = hoursLater(t, rise);
|
||||
if (set) result.set = hoursLater(t, set);
|
||||
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
|
||||
return result;
|
||||
};
|
||||
|
||||
function getMPhaseComp (offset) {
|
||||
var result = {};
|
||||
if (rise) result.rise = hoursLater(t, rise);
|
||||
if (set) result.set = hoursLater(t, set);
|
||||
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
|
||||
return result;
|
||||
};
|
||||
|
||||
function getMPhaseComp (offset) {
|
||||
var date = new Date();
|
||||
date.setDate(date.getDate() + offset);
|
||||
var dd = String(date.getDate());
|
||||
|
@ -222,9 +219,9 @@ function getImg(i) {
|
|||
var yyyy = date.getFullYear();
|
||||
var phase = SunCalc.getMoonIllumination(date);
|
||||
return dd + "." + mm + "." + yyyy + ": "+ phase.name;
|
||||
}
|
||||
|
||||
function getMPhaseSim (offset) {
|
||||
}
|
||||
|
||||
function getMPhaseSim (offset) {
|
||||
var date = new Date();
|
||||
date.setDate(date.getDate() + offset);
|
||||
var dd = String(date.getDate());
|
||||
|
@ -234,63 +231,123 @@ function getImg(i) {
|
|||
var yyyy = date.getFullYear();
|
||||
var phase = SunCalc.getMoonIllumination(date);
|
||||
return phase.name;
|
||||
}
|
||||
|
||||
function drawMoonPhase(offset, x, y){
|
||||
if (lat >= 0 && lat <= 90){ //Northern hemisphere
|
||||
if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-gibbous") {g.drawImage(getImg("WaxingGibbousNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "full") {g.drawImage(getImg("FullMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentNorth"), x, y);}
|
||||
}
|
||||
}
|
||||
|
||||
function drawMoonPhase(offset, x, y){
|
||||
if (coords.lat >= 0 && coords.lat <= 90){ //Northern hemisphere
|
||||
if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-gibbous") {g.drawImage(getImg("WaxingGibbousNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "full") {g.drawImage(getImg("FullMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterNorth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentNorth"), x, y);}
|
||||
}
|
||||
else { //Southern hemisphere
|
||||
if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-gibbous") {g.drawImage(getImg("WaxingGibbousSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "full") {g.drawImage(getImg("FullMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waxing-gibbous") {g.drawImage(getImg("WaxingGibbousSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "full") {g.drawImage(getImg("FullMoon"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterSouth"), x, y);}
|
||||
if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentSouth"), x, y);}
|
||||
}
|
||||
}
|
||||
|
||||
function drawMoon(offset, x, y) {
|
||||
}
|
||||
|
||||
function drawMoon(offset, x, y) {
|
||||
g.setFont("6x8");
|
||||
g.clear();
|
||||
g.drawString("Key1: increase day, Key3:decrease day",10,10);
|
||||
g.drawString(getMPhaseComp(offset),x,y-10);
|
||||
drawMoonPhase(offset, x, y);
|
||||
g.drawString("Key1: day+, Key2:today, Key3:day-",x,y-30);
|
||||
g.drawString("Last known coordinates: " + coords.lat.toFixed(4) + " " + coords.lon.toFixed(4), x, y-20);
|
||||
g.drawString("Press BTN4 to update",x, y-10);
|
||||
|
||||
g.drawString(getMPhaseComp(offset),x,y+30);
|
||||
drawMoonPhase(offset, x+35, y+40);
|
||||
|
||||
g.drawString(getMPhaseComp(offset+2),x,y+40);
|
||||
drawMoonPhase(offset+2, x, y+50);
|
||||
g.drawString(getMPhaseComp(offset+2),x,y+70);
|
||||
drawMoonPhase(offset+2, x+35, y+80);
|
||||
|
||||
g.drawString(getMPhaseComp(offset+4),x,y+90);
|
||||
drawMoonPhase(offset+4, x, y+100);
|
||||
g.drawString(getMPhaseComp(offset+4),x,y+110);
|
||||
drawMoonPhase(offset+4, x+35, y+120);
|
||||
|
||||
g.drawString(getMPhaseComp(offset+6),x,y+140);
|
||||
drawMoonPhase(offset+6, x, y+150);
|
||||
}
|
||||
|
||||
function start() {
|
||||
g.drawString(getMPhaseComp(offset+6),x,y+150);
|
||||
drawMoonPhase(offset+6, x+35, y+160);
|
||||
}
|
||||
|
||||
//Write coordinates to file
|
||||
function updateCoords() {
|
||||
storage.write('coords.json', coords);
|
||||
}
|
||||
|
||||
//set coordinates to default (city where I live)
|
||||
function resetCoords() {
|
||||
coords = {
|
||||
lat : 52.96236,
|
||||
lon : 7.62571,
|
||||
};
|
||||
updateCoords();
|
||||
}
|
||||
|
||||
function getGpsFix() {
|
||||
Bangle.on('GPS', function(fix) {
|
||||
g.clear();
|
||||
|
||||
if (fix.fix == 1) {
|
||||
var gpsString = "lat: " + fix.lat.toFixed(4) + " lon: " + fix.lon.toFixed(4);
|
||||
coords.lat = fix.lat;
|
||||
coords.lon = fix.lon;
|
||||
updateCoords();
|
||||
g.drawString("Got GPS fix and wrote coords to file",10,20);
|
||||
g.drawString(gpsString,10,30);
|
||||
g.drawString("Press BTN5 to return to app",10,40);
|
||||
clearInterval(timer);
|
||||
timer = undefined;
|
||||
}
|
||||
else {
|
||||
g.drawString("Searching satellites...",10,20);
|
||||
g.drawString("Press BTN5 to stop GPS",10, 30);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function start() {
|
||||
var x = 10;
|
||||
var y = 40;
|
||||
var y = 50;
|
||||
var offsetMoon = 0;
|
||||
coords = storage.readJSON('coords.json',1); //read coordinates from file
|
||||
if (!coords) resetCoords(); //if coordinates could not be read, reset them
|
||||
drawMoon(offsetMoon, x, y); //offset, x, y
|
||||
|
||||
|
||||
//define button functions
|
||||
setWatch(function() {
|
||||
setWatch(function() { //BTN1
|
||||
offsetMoon++; //jump to next day
|
||||
drawMoon(offsetMoon, x, y); //offset, x, y
|
||||
}, BTN1, {edge:"rising", debounce:50, repeat:true});
|
||||
setWatch(function() {
|
||||
|
||||
setWatch(function() { //BTN2
|
||||
offsetMoon = 0; //jump to today
|
||||
drawMoon(offsetMoon, x, y); //offset, x, y
|
||||
}, BTN2, {edge:"rising", debounce:50, repeat:true});
|
||||
|
||||
setWatch(function() { //BTN3
|
||||
offsetMoon--; //jump to next day
|
||||
drawMoon(offsetMoon, x, y); //offset, x, y
|
||||
}, BTN3, {edge:"rising", debounce:50, repeat:true});
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
setWatch(function() { //BTN4
|
||||
g.drawString("--- Getting GPS signal ---",x, y);
|
||||
Bangle.setGPSPower(1);
|
||||
timer = setInterval(getGpsFix, 10000);
|
||||
}, BTN4, {edge:"rising", debounce:50, repeat:true});
|
||||
|
||||
setWatch(function() { //BTN5
|
||||
if (timer) clearInterval(timer);
|
||||
timer = undefined;
|
||||
Bangle.setGPSPower(0);
|
||||
drawMoon(offsetMoon, x, y); //offset, x, y
|
||||
}, BTN5, {edge:"rising", debounce:50, repeat:true});
|
||||
}
|
||||
|
||||
start();
|
|
@ -0,0 +1 @@
|
|||
0.01: First release
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwgMJgMQgMZzOREaERiERzIACiIVOAIIUCz///ORgIXNIQIAC/4ABJJYsBCogYEAYMQiAWGLAoAJJI8JLAYoCAAgJBJIIwGBohxBJI4YBJIwOFC4w5EC4hdOzIgCyLFDC45hHAAZJDgJAKMQwyBSYSOBxIXGPRTdChOfxChHbpRhBC4P5GAgAOgEZFAKjIBAz1EC5YYJxAvBJ4IXQzGIxEQB4RbPCoOIwEAOKAsCC4QvCFiAXDdwwsMC5eebogVGAALWBC42f/AWLC4zwCUgIEBCxK+DE4bsFC5+f/IrBC4RzHXwkZzATEDgP/RZAXFz5ECf4oXMCYKICC6hABMAQXOgAXBLgLrHRxZfCC6sBCo4XLLwIXBbAgXRMIQAGRxgwChIXVgEQIYimOGAZ6CSgOJC6CrCC4TZBC6IwCC4QWQPQYXKOggAFPQOfC5AWKPQgXGCpR6FOwoWOPQQXDIZYwHC4QVRAAQXBBxgA="))
|
|
@ -0,0 +1,86 @@
|
|||
const dice = [4, 6, 8, 10, 12, 20, 100];
|
||||
const nFlips = 20;
|
||||
const delay = 500;
|
||||
|
||||
let dieIndex = 1;
|
||||
let face = 0;
|
||||
let rolling = false;
|
||||
|
||||
let bgColor;
|
||||
let fgColor;
|
||||
|
||||
function getDie() {
|
||||
return dice[dieIndex];
|
||||
}
|
||||
|
||||
function setColors(lastBounce) {
|
||||
if (lastBounce) {
|
||||
bgColor = 0xFFFF;
|
||||
fgColor = 0x0000;
|
||||
} else {
|
||||
bgColor = 0x0000
|
||||
fgColor = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
function flipFace() {
|
||||
while(true) {
|
||||
let newFace = Math.floor(Math.random() * getDie()) + 1;
|
||||
if (newFace !== face) {
|
||||
face = newFace;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
g.setColor(bgColor);
|
||||
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||
g.setColor(fgColor);
|
||||
g.setFontAlign(0, 0);
|
||||
g.setFontVector(40);
|
||||
g.drawString('d' + getDie(), 180, 30);
|
||||
g.setFontVector(100);
|
||||
g.drawString(face, 120, 120);
|
||||
}
|
||||
|
||||
function roll(bounces) {
|
||||
flipFace();
|
||||
setColors(bounces === 0);
|
||||
draw();
|
||||
if (bounces > 0) {
|
||||
setTimeout(() => roll(bounces - 1), delay / bounces);
|
||||
} else {
|
||||
rolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
function startRolling() {
|
||||
if (rolling) return;
|
||||
rolling = true;
|
||||
roll(nFlips);
|
||||
}
|
||||
|
||||
function changeDie() {
|
||||
if (rolling) return;
|
||||
dieIndex = (dieIndex + 1) % dice.length;
|
||||
draw();
|
||||
}
|
||||
|
||||
Bangle.on('lcdPower',function(on) {
|
||||
if (on) {
|
||||
startRolling();
|
||||
}
|
||||
});
|
||||
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
startRolling();
|
||||
|
||||
// Top button rolls the die, bottom button changes it
|
||||
setWatch(startRolling, BTN1, {repeat:true});
|
||||
setWatch(changeDie, BTN3, {repeat:true});
|
||||
|
||||
// Show launcher when middle button pressed
|
||||
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
|
After Width: | Height: | Size: 6.3 KiB |
|
@ -3,3 +3,5 @@
|
|||
Lap log now scrolls into 2nd column after 18th entry, able to display 36 entries before going off screen
|
||||
0.03: Added ability to save Lap log as a date named JSON file into memory
|
||||
Fixed bug from 0.01 where BN1 (reset) could clear the lap log when timer is running
|
||||
0.04: Changed save file filename, add interface.html to allow laps to be loaded
|
||||
0.05: Added widgets
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="records"></div>
|
||||
|
||||
<script src="../../lib/interface.js"></script>
|
||||
<script>
|
||||
var domRecords = document.getElementById("records");
|
||||
|
||||
function getLapTimes() {
|
||||
Util.showModal("Loading Lap Times...");
|
||||
domRecords.innerHTML = "";
|
||||
Puck.eval('require("Storage").list(/^swatch.*\.json/).map(fn=>({n:fn,d:require("Storage").readJSON(fn,1)}))',lapData=>{
|
||||
var html = `<div class="container">
|
||||
<div class="columns">\n`;
|
||||
lapData.forEach((lap,lapIndex) => {
|
||||
lap.date = lap.n.substr(7,16).replace("_"," ");
|
||||
html += `
|
||||
<div class="column col-12">
|
||||
<div class="card-header">
|
||||
<div class="card-title h5">${lap.date}</div>
|
||||
<div class="card-subtitle text-gray">${lap.d.length} Laps</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>lap</th>
|
||||
<th>time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${ lap.d.map((d,n)=>`<tr><td>${n+1}</td><td>${d}</td></tr>`).join("\n") }
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-primary" idx="${lapIndex}" task="download">Download</button>
|
||||
<button class="btn btn-default" idx="${lapIndex}" task="delete">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
if (lapData.length==0) {
|
||||
html += `
|
||||
<div class="column col-12">
|
||||
<div class="card-header">
|
||||
<div class="card-title h5">No record</div>
|
||||
<div class="card-subtitle text-gray">No laps recorded</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
html += `
|
||||
</div>
|
||||
</div>`;
|
||||
domRecords.innerHTML = html;
|
||||
Util.hideModal();
|
||||
var buttons = domRecords.querySelectorAll("button");
|
||||
for (var i=0;i<buttons.length;i++) {
|
||||
buttons[i].addEventListener("click",event => {
|
||||
var button = event.currentTarget;
|
||||
var lapIndex = parseInt(button.getAttribute("idx"));
|
||||
var lap = lapData[lapIndex];
|
||||
if (!lap) throw new Error("Invalid index!");
|
||||
var task = button.getAttribute("task");
|
||||
if (task=="delete") {
|
||||
Util.showModal("Deleting lap time...");
|
||||
Util.eraseStorage(lap.n,()=>{
|
||||
Util.hideModal();
|
||||
getLapTimes();
|
||||
});
|
||||
}
|
||||
if (task=="download") {
|
||||
Util.saveCSV(lap.n.slice(0,-5)+".csv", lap.d.map((d,n)=>[n+1,d].join(",")).join("\n"));
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
getLapTimes();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -4,7 +4,6 @@ var started = false;
|
|||
var timeY = 60;
|
||||
var hsXPos = 0;
|
||||
var lapTimes = [];
|
||||
var saveTimes = [];
|
||||
var displayInterval;
|
||||
|
||||
function timeToText(t) {
|
||||
|
@ -14,24 +13,26 @@ function timeToText(t) {
|
|||
return mins+":"+("0"+secs).substr(-2)+"."+("0"+hs).substr(-2);
|
||||
}
|
||||
function updateLabels() {
|
||||
g.clear();
|
||||
g.reset(1);
|
||||
g.clearRect(0,23,g.getWidth()-1,g.getHeight()-24);
|
||||
g.setFont("6x8",2);
|
||||
g.setFontAlign(0,0,3);
|
||||
g.drawString(started?"STOP":"GO",230,120);
|
||||
if (!started) g.drawString("RESET",230,190);
|
||||
if (!started) g.drawString("RESET",230,180);
|
||||
g.drawString(started?"LAP":"SAVE",230,50);
|
||||
g.setFont("6x8",1);
|
||||
g.setFontAlign(-1,-1);
|
||||
for (var i in lapTimes) {
|
||||
if (i<18)
|
||||
if (i<16)
|
||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 30 + i*8);}
|
||||
else
|
||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 30 + (i-18)*8);}
|
||||
else if (i<32)
|
||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 30 + (i-16)*8);}
|
||||
}
|
||||
drawsecs();
|
||||
}
|
||||
function drawsecs() {
|
||||
var t = tCurrent-tStart;
|
||||
g.reset(1);
|
||||
g.setFont("Vector",48);
|
||||
g.setFontAlign(0,0);
|
||||
var secs = Math.floor(t/1000)%60;
|
||||
|
@ -51,10 +52,8 @@ function drawms() {
|
|||
g.clearRect(hsXPos,timeY,220,timeY+20);
|
||||
g.drawString("."+("0"+hs).substr(-2),hsXPos,timeY+10);
|
||||
}
|
||||
function saveconvert() {
|
||||
for (var v in lapTimes){
|
||||
saveTimes[v]=v+1+"-"+timeToText(lapTimes[(lapTimes.length-1)-v]);
|
||||
}
|
||||
function getLapTimesArray() {
|
||||
return lapTimes.map(timeToText).reverse();
|
||||
}
|
||||
|
||||
setWatch(function() { // Start/stop
|
||||
|
@ -80,16 +79,21 @@ setWatch(function() { // Start/stop
|
|||
}, BTN2, {repeat:true});
|
||||
setWatch(function() { // Lap
|
||||
Bangle.beep();
|
||||
if (started) tCurrent = Date.now();
|
||||
lapTimes.unshift(tCurrent-tStart);
|
||||
tStart = tCurrent;
|
||||
if (!started)
|
||||
{
|
||||
var timenow= Date();
|
||||
saveconvert();
|
||||
require("Storage").writeJSON("StpWch-"+timenow.toString(), saveTimes);
|
||||
if (started) {
|
||||
tCurrent = Date.now();
|
||||
lapTimes.unshift(tCurrent-tStart);
|
||||
}
|
||||
tStart = tCurrent;
|
||||
if (!started) { // save
|
||||
var timenow= Date();
|
||||
var filename = "swatch-"+(new Date()).toISOString().substr(0,16).replace("T","_")+".json";
|
||||
// this maxes out the 28 char maximum
|
||||
require("Storage").writeJSON(filename, getLapTimesArray());
|
||||
E.showMessage("Laps Saved","Stopwatch");
|
||||
setTimeout(updateLabels, 1000);
|
||||
} else {
|
||||
updateLabels();
|
||||
}
|
||||
updateLabels();
|
||||
}, BTN1, {repeat:true});
|
||||
setWatch(function() { // Reset
|
||||
if (!started) {
|
||||
|
@ -101,3 +105,5 @@ setWatch(function() { // Reset
|
|||
}, BTN3, {repeat:true});
|
||||
|
||||
updateLabels();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New App!
|
||||
0.02: Add swipe support and doucle tap to run application
|
|
@ -0,0 +1,130 @@
|
|||
g.clear();
|
||||
|
||||
const Storage = require("Storage");
|
||||
|
||||
function getApps(){
|
||||
return Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) })
|
||||
.filter(app=>app.type=="app" || app.type=="clock" || !app.type)
|
||||
.sort((a,b)=>{
|
||||
var n=(0|a.sortorder)-(0|b.sortorder);
|
||||
if (n) return n; // do sortorder first
|
||||
if (a.name<b.name) return -1;
|
||||
if (a.name>b.name) return 1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
const selected = 0;
|
||||
const apps = getApps();
|
||||
|
||||
function prev(){
|
||||
if (selected>=0) {
|
||||
selected--;
|
||||
}
|
||||
drawMenu();
|
||||
}
|
||||
|
||||
function next() {
|
||||
if (selected+1<apps.length) {
|
||||
selected++;
|
||||
}
|
||||
drawMenu();
|
||||
}
|
||||
|
||||
function run() {
|
||||
if(selected < 0) return load();
|
||||
if (!apps[selected].src) return;
|
||||
if (Storage.read(apps[selected].src)===undefined) {
|
||||
E.showMessage("App Source\nNot found");
|
||||
setTimeout(drawMenu, 2000);
|
||||
} else {
|
||||
E.showMessage("Loading...");
|
||||
load(apps[selected].src);
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentApp(){
|
||||
return apps[selected];
|
||||
}
|
||||
|
||||
function getNextApp(){
|
||||
return apps[selected+1];
|
||||
}
|
||||
|
||||
function drawFallbackIcon(){
|
||||
g.setColor(1,1,1);
|
||||
g.fillRect(72, 40, 168, 136);
|
||||
g.setColor(0,0,0);
|
||||
g.setFont('6x8', 8);
|
||||
g.drawString('?', 124, 88);
|
||||
}
|
||||
|
||||
function drawArrow(x, y, size, dir){
|
||||
size = size || 10;
|
||||
dir = dir || 1;
|
||||
g.moveTo(x, y).lineTo(x+(size*dir), y-size).lineTo(x+(size*dir),y+size).lineTo(x, y);
|
||||
}
|
||||
|
||||
function drawMenu(){
|
||||
|
||||
if(selected < 0){
|
||||
g.clear();
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont('6x8', 2);
|
||||
g.drawString('Back', 120, 120);
|
||||
drawArrow(220, 120, 10, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
const app = getCurrentApp();
|
||||
g.clear();
|
||||
g.setFontAlign(0,0);
|
||||
g.setFont('6x8', 2);
|
||||
if(!app) return g.drawString('???', 120, 120);
|
||||
g.drawString(app.name, 120, 160);
|
||||
if (app.icon) icon = Storage.read(app.icon);
|
||||
if (icon) try {g.drawImage(icon, 120-48, 40, { scale: 2 });} catch(e){ drawFallbackIcon(); }
|
||||
else drawFallbackIcon();
|
||||
|
||||
g.setFont('6x8', 1);
|
||||
|
||||
const type = app.type ? app.type : 'App';
|
||||
const version = app.version ? app.version : '0.00';
|
||||
const info = type+' v'+version;
|
||||
g.setFontAlign(-1,1);
|
||||
g.drawString(info, 20, 220);
|
||||
|
||||
const count = (selected+1)+'/'+apps.length;
|
||||
g.setFontAlign(1,1);
|
||||
g.drawString(count, 220, 220);
|
||||
|
||||
drawArrow(20, 120, 10, 1);
|
||||
if(getNextApp()) drawArrow(220, 120, 10, -1);
|
||||
}
|
||||
|
||||
drawMenu();
|
||||
|
||||
// Physical buttons
|
||||
setWatch(prev, BTN1, {repeat:true});
|
||||
setWatch(next, BTN3, {repeat:true});
|
||||
setWatch(run, BTN2, {repeat:true,edge:"falling"});
|
||||
|
||||
// Screen event
|
||||
Bangle.on('touch', function(button){
|
||||
switch(button){
|
||||
case 1:
|
||||
prev();
|
||||
break;
|
||||
case 2:
|
||||
next();
|
||||
break;
|
||||
case 3:
|
||||
run();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.on('swipe', dir => {
|
||||
if(dir == 1) prev();
|
||||
else next();
|
||||
});
|
After Width: | Height: | Size: 695 B |
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
|
@ -0,0 +1,33 @@
|
|||
/* jshint esversion: 6 */
|
||||
(() => {
|
||||
|
||||
const BLACK = 0, MOON = 0x41f, MC = 29.5305882, NM = 694039.09;
|
||||
var r = 12, mx = 0, my = 0;
|
||||
|
||||
var moon = {
|
||||
0: () => { g.reset().setColor(BLACK).fillRect(mx - r, my - r, mx + r, my + r);},
|
||||
1: () => { moon[0](); g.setColor(MOON).drawCircle(mx, my, r);},
|
||||
2: () => { moon[3](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);},
|
||||
3: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx - r, my - r, mx, my + r);},
|
||||
4: () => { moon[3](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);},
|
||||
5: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r);},
|
||||
6: () => { moon[7](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);},
|
||||
7: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx, my - r, mx + r + r, my + r);},
|
||||
8: () => { moon[7](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}
|
||||
};
|
||||
|
||||
function moonPhase(d) {
|
||||
var tmp, month = d.getMonth(), year = d.getFullYear(), day = d.getDate();
|
||||
if (month < 3) {year--; month += 12;}
|
||||
tmp = ((365.25 * year + 30.6 * ++month + day - NM) / MC);
|
||||
return Math.round(((tmp - (tmp | 0)) * 7)+1);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
mx = this.x; my = this.y + 12;
|
||||
moon[moonPhase(Date())]();
|
||||
}
|
||||
|
||||
WIDGETS["widmoon"] = { area: "tr", width: 24, draw: draw };
|
||||
|
||||
})();
|
After Width: | Height: | Size: 2.0 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#5755d9</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 860 B |
BIN
favicon.ico
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,9 @@
|
|||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5755d9">
|
||||
<meta name="apple-mobile-web-app-title" content="BangleApps">
|
||||
<meta name="application-name" content="BangleApps">
|
||||
<meta name="msapplication-TileColor" content="#5755d9">
|
||||
<meta name="theme-color" content="#5755d9">
|
12
index.html
|
@ -6,6 +6,15 @@
|
|||
<link rel="stylesheet" href="css/spectre.min.css">
|
||||
<link rel="stylesheet" href="css/spectre-exp.min.css">
|
||||
<link rel="stylesheet" href="css/spectre-icons.min.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5755d9">
|
||||
<meta name="apple-mobile-web-app-title" content="BangleApps">
|
||||
<meta name="application-name" content="BangleApps">
|
||||
<meta name="msapplication-TileColor" content="#5755d9">
|
||||
<meta name="theme-color" content="#5755d9">
|
||||
<title>Bangle.js App Loader</title>
|
||||
<style>
|
||||
.navbar { background-color: #5755d9; padding: 0.5em 1em 0.5em 1em; }
|
||||
|
@ -117,7 +126,7 @@
|
|||
</div>
|
||||
<div class="container" style="padding-top: 8px;">
|
||||
<p>Check out <a href="https://github.com/espruino/BangleApps" target="_blank">the Source on GitHub</a>, or
|
||||
find out <a href="https://www.espruino.com/Bangle.js+App+Loader" target="_blank">how to add your own app</p>
|
||||
find out <a href="https://www.espruino.com/Bangle.js+App+Loader" target="_blank">how to add your own app</a></p>
|
||||
<p>Using <a href="https://espruino.com/" target="_blank">Espruino</a>, Icons from <a href="https://icons8.com/" target="_blank">icons8.com</a></p>
|
||||
|
||||
<h3>Utilities</h3>
|
||||
|
@ -129,6 +138,7 @@
|
|||
|
||||
<script src="https://www.puck-js.com/puck.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/ui.js"></script>
|
||||
<script src="js/comms.js"></script>
|
||||
<script src="js/appinfo.js"></script>
|
||||
<script src="js/index.js"></script>
|
||||
|
|
41
js/comms.js
|
@ -9,14 +9,19 @@ reset : (opt) => new Promise((resolve,reject) => {
|
|||
});
|
||||
}),
|
||||
uploadApp : (app,skipReset) => {
|
||||
Progress.show({title:`Uploading ${app.name}`,sticky:true});
|
||||
return AppInfo.getFiles(app, httpGet).then(fileContents => {
|
||||
return new Promise((resolve,reject) => {
|
||||
console.log("uploadApp",fileContents.map(f=>f.name).join(", "));
|
||||
var maxBytes = fileContents.reduce((b,f)=>b+f.content.length, 0)||1;
|
||||
var currentBytes = 0;
|
||||
|
||||
// Upload each file one at a time
|
||||
function doUploadFiles() {
|
||||
// No files left - print 'reboot' message
|
||||
if (fileContents.length==0) {
|
||||
Puck.write(`\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => {
|
||||
Progress.hide({sticky:true});
|
||||
if (result===null) return reject("");
|
||||
resolve(app);
|
||||
});
|
||||
|
@ -24,17 +29,27 @@ uploadApp : (app,skipReset) => {
|
|||
}
|
||||
var f = fileContents.shift();
|
||||
console.log(`Upload ${f.name} => ${JSON.stringify(f.content)}`);
|
||||
Progress.show({
|
||||
min:currentBytes / maxBytes,
|
||||
max:(currentBytes+f.content.length) / maxBytes});
|
||||
currentBytes += f.content.length;
|
||||
// Chould check CRC here if needed instead of returning 'OK'...
|
||||
// E.CRC32(require("Storage").read(${JSON.stringify(app.name)}))
|
||||
Puck.write(`\x10${f.cmd};Bluetooth.println("OK")\n`,(result) => {
|
||||
if (!result || result.trim()!="OK") return reject("Unexpected response "+(result||""));
|
||||
if (!result || result.trim()!="OK") {
|
||||
Progress.hide({sticky:true});
|
||||
return reject("Unexpected response "+(result||""));
|
||||
}
|
||||
doUploadFiles();
|
||||
}, true); // wait for a newline
|
||||
}
|
||||
// Start the upload
|
||||
function doUpload() {
|
||||
Puck.write(`\x10E.showMessage('Uploading\\n${app.id}...')\n`,(result) => {
|
||||
if (result===null) return reject("");
|
||||
if (result===null) {
|
||||
Progress.hide({sticky:true});
|
||||
return reject("");
|
||||
}
|
||||
doUploadFiles();
|
||||
});
|
||||
}
|
||||
|
@ -48,10 +63,15 @@ uploadApp : (app,skipReset) => {
|
|||
});
|
||||
},
|
||||
getInstalledApps : () => {
|
||||
Progress.show({title:`Getting app list...`,sticky:true});
|
||||
return new Promise((resolve,reject) => {
|
||||
Puck.write("\x03",(result) => {
|
||||
if (result===null) return reject("");
|
||||
if (result===null) {
|
||||
Progress.hide({sticky:true});
|
||||
return reject("");
|
||||
}
|
||||
Puck.eval('require("Storage").list(/\.info$/).map(f=>{var j=require("Storage").readJSON(f,1)||{};j.id=f.slice(0,-5);return j})', (appList,err) => {
|
||||
Progress.hide({sticky:true});
|
||||
if (appList===null) return reject(err || "");
|
||||
console.log("getInstalledApps", appList);
|
||||
resolve(appList);
|
||||
|
@ -60,6 +80,7 @@ getInstalledApps : () => {
|
|||
});
|
||||
},
|
||||
removeApp : app => { // expects an app structure
|
||||
Progress.show({title:`Removing ${app.name}`,sticky:true});
|
||||
var storage = [{name:app.id+".info"}].concat(app.storage);
|
||||
var cmds = storage.map(file=>{
|
||||
return `\x10require("Storage").erase(${toJS(file.name)});\n`;
|
||||
|
@ -67,15 +88,21 @@ removeApp : app => { // expects an app structure
|
|||
console.log("removeApp", cmds);
|
||||
return Comms.reset().then(new Promise((resolve,reject) => {
|
||||
Puck.write(`\x03\x10E.showMessage('Erasing\\n${app.id}...')${cmds}\x10E.showMessage('Hold BTN3\\nto reload')\n`,(result) => {
|
||||
Progress.hide({sticky:true});
|
||||
if (result===null) return reject("");
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
})).catch(function(reason) {
|
||||
Progress.hide({sticky:true});
|
||||
return Promise.reject(reason);
|
||||
});
|
||||
},
|
||||
removeAllApps : () => {
|
||||
Progress.show({title:"Removing all apps",progess:"animate",sticky:true});
|
||||
return new Promise((resolve,reject) => {
|
||||
// Use write with newline here so we wait for it to finish
|
||||
Puck.write('\x10E.showMessage("Erasing...");require("Storage").eraseAll();Bluetooth.println("OK");reset()\n', (result,err) => {
|
||||
Progress.hide({sticky:true});
|
||||
if (!result || result.trim()!="OK") return reject(err || "");
|
||||
resolve();
|
||||
}, true /* wait for newline */);
|
||||
|
@ -171,10 +198,10 @@ readStorageFile : (filename) => { // StorageFiles are different to normal storag
|
|||
fileContent = fileContent.substr(newLineIdx+1);
|
||||
}
|
||||
} else {
|
||||
showProgress(undefined,100*fileContent.length / (fileSize||1000000));
|
||||
Progress.show({percent:100*fileContent.length / (fileSize||1000000)});
|
||||
}
|
||||
if (finished) {
|
||||
hideProgress();
|
||||
Progress.hide();
|
||||
connection.received = "";
|
||||
connection.cb = undefined;
|
||||
resolve(fileContent);
|
||||
|
@ -188,7 +215,7 @@ readStorageFile : (filename) => { // StorageFiles are different to normal storag
|
|||
while (l!==undefined) { Bluetooth.print(l); l = f.readLine(); }
|
||||
Bluetooth.print("\xFF");
|
||||
})()\n`,() => {
|
||||
showProgress(`Reading ${JSON.stringify(filename)}`,0);
|
||||
Progress.show({title:`Reading ${JSON.stringify(filename)}`,percent:0});
|
||||
console.log(`StorageFile read started...`);
|
||||
});
|
||||
});
|
||||
|
|
144
js/index.js
|
@ -14,119 +14,7 @@ httpGet("apps.json").then(apps=>{
|
|||
refreshFilter();
|
||||
});
|
||||
|
||||
// Status
|
||||
// =========================================== Top Navigation
|
||||
function showToast(message, type) {
|
||||
// toast-primary, toast-success, toast-warning or toast-error
|
||||
var style = "toast-primary";
|
||||
if (type=="success") style = "toast-success";
|
||||
else if (type=="error") style = "toast-error";
|
||||
else if (type!==undefined) console.log("showToast: unknown toast "+type);
|
||||
var toastcontainer = document.getElementById("toastcontainer");
|
||||
var msgDiv = htmlElement(`<div class="toast ${style}"></div>`);
|
||||
msgDiv.innerHTML = message;
|
||||
toastcontainer.append(msgDiv);
|
||||
setTimeout(function() {
|
||||
msgDiv.remove();
|
||||
}, 5000);
|
||||
}
|
||||
var progressToast; // the DOM element
|
||||
var progressSticky; // showProgress(,,"sticky") don't remove until hideProgress("sticky")
|
||||
var progressInterval; // the interval used if showProgress(..., "animate")
|
||||
var progressPercent; // the current progress percentage
|
||||
function showProgress(text, percent, sticky) {
|
||||
if (sticky=="sticky")
|
||||
progressSticky = true;
|
||||
if (!progressToast) {
|
||||
if (progressInterval) {
|
||||
clearInterval(progressInterval);
|
||||
progressInterval = undefined;
|
||||
}
|
||||
if (percent == "animate") {
|
||||
progressInterval = setInterval(function() {
|
||||
progressPercent += 2;
|
||||
if (progressPercent>100) progressPercent=0;
|
||||
showProgress(undefined, progressPercent);
|
||||
}, 100);
|
||||
percent = 0;
|
||||
}
|
||||
progressPercent = percent;
|
||||
|
||||
var toastcontainer = document.getElementById("toastcontainer");
|
||||
progressToast = htmlElement(`<div class="toast">
|
||||
${text ? `<div>${text}</div>`:``}
|
||||
<div class="bar bar-sm">
|
||||
<div class="bar-item" id="progressToast" role="progressbar" style="width:${percent}%;" aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>`);
|
||||
toastcontainer.append(progressToast);
|
||||
} else {
|
||||
var pt=document.getElementById("progressToast");
|
||||
pt.setAttribute("aria-valuenow",percent);
|
||||
pt.style.width = percent+"%";
|
||||
}
|
||||
}
|
||||
function hideProgress(sticky) {
|
||||
if (progressSticky && sticky!="sticky")
|
||||
return;
|
||||
progressSticky = false;
|
||||
if (progressInterval) {
|
||||
clearInterval(progressInterval);
|
||||
progressInterval = undefined;
|
||||
}
|
||||
if (progressToast) progressToast.remove();
|
||||
progressToast = undefined;
|
||||
}
|
||||
|
||||
Puck.writeProgress = function(charsSent, charsTotal) {
|
||||
if (charsSent===undefined) {
|
||||
hideProgress();
|
||||
return;
|
||||
}
|
||||
var percent = Math.round(charsSent*100/charsTotal);
|
||||
showProgress(undefined, percent);
|
||||
}
|
||||
function showPrompt(title, text, buttons) {
|
||||
if (!buttons) buttons={yes:1,no:1};
|
||||
return new Promise((resolve,reject) => {
|
||||
var modal = htmlElement(`<div class="modal active">
|
||||
<!--<a href="#close" class="modal-overlay" aria-label="Close"></a>-->
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<a href="#close" class="btn btn-clear float-right" aria-label="Close"></a>
|
||||
<div class="modal-title h5">${escapeHtml(title)}</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="content">
|
||||
${escapeHtml(text).replace(/\n/g,'<br/>')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="modal-footer">
|
||||
${buttons.yes?'<button class="btn btn-primary" isyes="1">Yes</button>':''}
|
||||
${buttons.no?'<button class="btn" isyes="0">No</button>':''}
|
||||
${buttons.ok?'<button class="btn" isyes="1">Ok</button>':''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
document.body.append(modal);
|
||||
modal.querySelector("a[href='#close']").addEventListener("click",event => {
|
||||
event.preventDefault();
|
||||
reject("User cancelled");
|
||||
modal.remove();
|
||||
});
|
||||
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
|
||||
button.addEventListener("click",event => {
|
||||
event.preventDefault();
|
||||
var isYes = event.target.getAttribute("isyes")=="1";
|
||||
if (isYes) resolve();
|
||||
else reject("User cancelled");
|
||||
modal.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
function showChangeLog(appid) {
|
||||
var app = appNameToApp(appid);
|
||||
function show(contents) {
|
||||
|
@ -170,12 +58,11 @@ function handleCustomApp(appTemplate) {
|
|||
Object.keys(appFiles).forEach(k => app[k] = appFiles[k]);
|
||||
console.log("Received custom app", app);
|
||||
modal.remove();
|
||||
showProgress(`Uploading ${app.name}`,undefined,"sticky");
|
||||
Comms.uploadApp(app).then(()=>{
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
resolve();
|
||||
}).catch(e => {
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
reject(e);
|
||||
});
|
||||
}, false);
|
||||
|
@ -334,9 +221,8 @@ function refreshLibrary() {
|
|||
// upload
|
||||
icon.classList.remove("icon-upload");
|
||||
icon.classList.add("loading");
|
||||
showProgress(`Uploading ${app.name}`,undefined,"sticky");
|
||||
Comms.uploadApp(app).then((appJSON) => {
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
if (appJSON) appsInstalled.push(appJSON);
|
||||
showToast(app.name+" Uploaded!", "success");
|
||||
icon.classList.remove("loading");
|
||||
|
@ -344,7 +230,7 @@ function refreshLibrary() {
|
|||
refreshMyApps();
|
||||
refreshLibrary();
|
||||
}).catch(err => {
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
showToast("Upload failed, "+err, "error");
|
||||
icon.classList.remove("loading");
|
||||
icon.classList.add("icon-upload");
|
||||
|
@ -403,19 +289,16 @@ function customApp(app) {
|
|||
|
||||
function updateApp(app) {
|
||||
if (app.custom) return customApp(app);
|
||||
showProgress(`Upgrading ${app.name}`,undefined,"sticky");
|
||||
return Comms.removeApp(app).then(()=>{
|
||||
showToast(app.name+" removed successfully. Updating...",);
|
||||
appsInstalled = appsInstalled.filter(a=>a.id!=app.id);
|
||||
return Comms.uploadApp(app);
|
||||
}).then((appJSON) => {
|
||||
hideProgress("sticky");
|
||||
if (appJSON) appsInstalled.push(appJSON);
|
||||
showToast(app.name+" Updated!", "success");
|
||||
refreshMyApps();
|
||||
refreshLibrary();
|
||||
}, err=>{
|
||||
hideProgress("sticky");
|
||||
showToast(app.name+" update failed, "+err,"error");
|
||||
refreshMyApps();
|
||||
refreshLibrary();
|
||||
|
@ -488,18 +371,15 @@ return `<div class="tile column col-6 col-sm-12 col-xs-12">
|
|||
|
||||
function getInstalledApps() {
|
||||
showLoadingIndicator("myappscontainer");
|
||||
showProgress(`Getting app list...`,undefined,"sticky");
|
||||
// Get apps and files
|
||||
return Comms.getInstalledApps()
|
||||
.then(appJSON => {
|
||||
hideProgress("sticky");
|
||||
appsInstalled = appJSON;
|
||||
refreshMyApps();
|
||||
refreshLibrary();
|
||||
})
|
||||
.then(() => handleConnectionChange(true))
|
||||
.catch(err=>{
|
||||
hideProgress("sticky");
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
@ -555,15 +435,14 @@ document.getElementById("settime").addEventListener("click",event=>{
|
|||
});
|
||||
document.getElementById("removeall").addEventListener("click",event=>{
|
||||
showPrompt("Remove All","Really remove all apps?").then(() => {
|
||||
showProgress("Removing all apps","animate", "sticky");
|
||||
return Comms.removeAllApps();
|
||||
}).then(()=>{
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
appsInstalled = [];
|
||||
showToast("All apps removed","success");
|
||||
return getInstalledApps();
|
||||
}).catch(err=>{
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
showToast("App removal failed, "+err,"error");
|
||||
});
|
||||
});
|
||||
|
@ -578,24 +457,23 @@ document.getElementById("installdefault").addEventListener("click",event=>{
|
|||
appCount = defaultApps.length;
|
||||
return showPrompt("Install Defaults","Remove everything and install default apps?");
|
||||
}).then(() => {
|
||||
showProgress("Removing all apps","animate", "sticky");
|
||||
return Comms.removeAllApps();
|
||||
}).then(()=>{
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
appsInstalled = [];
|
||||
showToast(`Existing apps removed. Installing ${appCount} apps...`);
|
||||
return new Promise((resolve,reject) => {
|
||||
function upload() {
|
||||
var app = defaultApps.shift();
|
||||
if (app===undefined) return resolve();
|
||||
showProgress(`${app.name} (${appCount-defaultApps.length}/${appCount})`,undefined,"sticky");
|
||||
Progress.show({title:`${app.name} (${appCount-defaultApps.length}/${appCount})`,sticky:true});
|
||||
Comms.uploadApp(app,"skip_reset").then((appJSON) => {
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
if (appJSON) appsInstalled.push(appJSON);
|
||||
showToast(`(${appCount-defaultApps.length}/${appCount}) ${app.name} Uploaded`);
|
||||
upload();
|
||||
}).catch(function() {
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
reject()
|
||||
});
|
||||
}
|
||||
|
@ -607,7 +485,7 @@ document.getElementById("installdefault").addEventListener("click",event=>{
|
|||
showToast("Default apps successfully installed!","success");
|
||||
return getInstalledApps();
|
||||
}).catch(err=>{
|
||||
hideProgress("sticky");
|
||||
Progress.hide({sticky:true});
|
||||
showToast("App Install failed, "+err,"error");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
// General UI tools (progress bar, toast, prompt)
|
||||
|
||||
/// Handle progress bars
|
||||
var Progress = {
|
||||
domElement : null, // the DOM element
|
||||
sticky : false, // Progress.show({..., sticky:true}) don't remove until Progress.hide({sticky:true})
|
||||
interval : undefined, // the interval used if Progress.show({progress:"animate"})
|
||||
percent : undefined, // the current progress percentage
|
||||
min : 0, // scaling for percentage
|
||||
max : 1, // scaling for percentage
|
||||
|
||||
/* Show a Progress message
|
||||
Progress.show({
|
||||
sticky : bool // keep showing text even when Progress.hide is called (unless Progress.hide({sticky:true}))
|
||||
percent : number | "animate"
|
||||
min : // minimum scale for percentage (default 0)
|
||||
max : // maximum scale for percentage (default 1)
|
||||
}) */
|
||||
show : function(options) {
|
||||
options = options||{};
|
||||
var text = options.title;
|
||||
if (options.sticky) Progress.sticky = true;
|
||||
if (options.min!==undefined) Progress.min = options.min;
|
||||
if (options.max!==undefined) Progress.max = options.max;
|
||||
var percent = options.percent;
|
||||
if (percent!==undefined)
|
||||
percent = Progress.min*100 + (Progress.max-Progress.min)*percent;
|
||||
if (!Progress.domElement) {
|
||||
if (Progress.interval) {
|
||||
clearInterval(Progress.interval);
|
||||
Progress.interval = undefined;
|
||||
}
|
||||
if (percent == "animate") {
|
||||
Progress.interval = setInterval(function() {
|
||||
Progress.percent += 2;
|
||||
if (Progress.percent>100) Progress.percent=0;
|
||||
Progress.show({percent:Progress.percent});
|
||||
}, 100);
|
||||
percent = 0;
|
||||
}
|
||||
|
||||
var toastcontainer = document.getElementById("toastcontainer");
|
||||
Progress.domElement = htmlElement(`<div class="toast">
|
||||
${text ? `<div>${text}</div>`:``}
|
||||
<div class="bar bar-sm">
|
||||
<div class="bar-item" id="Progress.domElement" role="progressbar" style="width:${percent}%;" aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>`);
|
||||
toastcontainer.append(Progress.domElement);
|
||||
} else {
|
||||
var pt=document.getElementById("Progress.domElement");
|
||||
pt.setAttribute("aria-valuenow",percent);
|
||||
pt.style.width = percent+"%";
|
||||
}
|
||||
},
|
||||
// Progress.hide({sticky:true}) undoes Progress.show({title:"title", sticky:true})
|
||||
hide : function(options) {
|
||||
options = options||{};
|
||||
if (Progress.sticky && !options.sticky)
|
||||
return;
|
||||
Progress.sticky = false;
|
||||
Progress.min = 0;
|
||||
Progress.max = 1;
|
||||
if (Progress.interval) {
|
||||
clearInterval(Progress.interval);
|
||||
Progress.interval = undefined;
|
||||
}
|
||||
if (Progress.domElement) Progress.domElement.remove();
|
||||
Progress.domElement = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/// Add progress handler so we get nice uploads
|
||||
Puck.writeProgress = function(charsSent, charsTotal) {
|
||||
if (charsSent===undefined) {
|
||||
Progress.hide();
|
||||
return;
|
||||
}
|
||||
var percent = Math.round(charsSent*100/charsTotal);
|
||||
Progress.show({percent: percent});
|
||||
}
|
||||
|
||||
/// Show a 'toast' message for status
|
||||
function showToast(message, type) {
|
||||
// toast-primary, toast-success, toast-warning or toast-error
|
||||
var style = "toast-primary";
|
||||
if (type=="success") style = "toast-success";
|
||||
else if (type=="error") style = "toast-error";
|
||||
else if (type!==undefined) console.log("showToast: unknown toast "+type);
|
||||
var toastcontainer = document.getElementById("toastcontainer");
|
||||
var msgDiv = htmlElement(`<div class="toast ${style}"></div>`);
|
||||
msgDiv.innerHTML = message;
|
||||
toastcontainer.append(msgDiv);
|
||||
setTimeout(function() {
|
||||
msgDiv.remove();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
/// Show a yes/no prompt
|
||||
function showPrompt(title, text, buttons) {
|
||||
if (!buttons) buttons={yes:1,no:1};
|
||||
return new Promise((resolve,reject) => {
|
||||
var modal = htmlElement(`<div class="modal active">
|
||||
<!--<a href="#close" class="modal-overlay" aria-label="Close"></a>-->
|
||||
<div class="modal-container">
|
||||
<div class="modal-header">
|
||||
<a href="#close" class="btn btn-clear float-right" aria-label="Close"></a>
|
||||
<div class="modal-title h5">${escapeHtml(title)}</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="content">
|
||||
${escapeHtml(text).replace(/\n/g,'<br/>')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="modal-footer">
|
||||
${buttons.yes?'<button class="btn btn-primary" isyes="1">Yes</button>':''}
|
||||
${buttons.no?'<button class="btn" isyes="0">No</button>':''}
|
||||
${buttons.ok?'<button class="btn" isyes="1">Ok</button>':''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
document.body.append(modal);
|
||||
modal.querySelector("a[href='#close']").addEventListener("click",event => {
|
||||
event.preventDefault();
|
||||
reject("User cancelled");
|
||||
modal.remove();
|
||||
});
|
||||
htmlToArray(modal.getElementsByTagName("button")).forEach(button => {
|
||||
button.addEventListener("click",event => {
|
||||
event.preventDefault();
|
||||
var isYes = event.target.getAttribute("isyes")=="1";
|
||||
if (isYes) resolve();
|
||||
else reject("User cancelled");
|
||||
modal.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -39,7 +39,10 @@ var Util = {
|
|||
window.postMessage({type:"readstoragefile",data:filename,id:__id});
|
||||
},
|
||||
eraseStorageFile : function(filename,callback) {
|
||||
Puck.write(`\x10require("Storage").open(${JSON.stringify(filename)}","r").erase()\n`,callback);
|
||||
Puck.write(`\x10require("Storage").open(${JSON.stringify(filename)},"r").erase()\n`,callback);
|
||||
},
|
||||
eraseStorage : function(filename,callback) {
|
||||
Puck.write(`\x10require("Storage").erase(${JSON.stringify(filename)})\n`,callback);
|
||||
},
|
||||
showModal : function(title) {
|
||||
if (!Util.domModal) {
|
||||
|
@ -66,6 +69,19 @@ var Util = {
|
|||
hideModal : function() {
|
||||
if (!Util.domModal) return;
|
||||
Util.domModal.classList.remove("active");
|
||||
},
|
||||
saveCSV : function(filename, csvData) {
|
||||
var a = document.createElement("a"),
|
||||
file = new Blob([csvData], {type: "Comma-separated value file"});
|
||||
var url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = filename+".csv";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function() {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", function(event) {
|
||||
|
|
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="960.000000pt" height="960.000000pt" viewBox="0 0 960.000000 960.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,960.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M3632 9573 c-94 -64 -135 -159 -146 -338 -3 -38 -7 -90 -10 -115 -3
|
||||
-25 -8 -70 -11 -100 -2 -30 -7 -77 -9 -105 -3 -27 -8 -79 -11 -115 -3 -36 -8
|
||||
-87 -11 -115 -8 -77 -14 -136 -18 -180 -4 -44 -14 -130 -20 -185 -3 -19 -10
|
||||
-80 -16 -135 -6 -55 -13 -111 -16 -125 -4 -25 -13 -91 -19 -140 -15 -123 -21
|
||||
-146 -47 -183 -31 -43 -47 -75 -52 -103 -3 -13 -7 -27 -9 -32 -10 -15 -19 -99
|
||||
-19 -174 l0 -77 -36 -23 c-96 -58 -185 -119 -276 -188 -54 -41 -108 -82 -120
|
||||
-90 -21 -15 -332 -326 -351 -351 -10 -13 -91 -116 -120 -151 -22 -27 -180
|
||||
-271 -193 -298 -7 -14 -29 -57 -50 -96 -42 -77 -134 -283 -148 -329 -2 -5 -10
|
||||
-30 -19 -55 -19 -52 -71 -223 -79 -260 -3 -14 -10 -43 -15 -65 -6 -22 -12 -53
|
||||
-15 -70 -3 -16 -8 -41 -11 -55 -9 -43 -17 -104 -32 -240 -16 -149 -9 -530 13
|
||||
-670 16 -101 34 -203 49 -270 21 -94 21 -92 27 -110 14 -42 39 -127 43 -145 2
|
||||
-11 12 -41 24 -68 11 -26 21 -51 22 -55 1 -4 5 -17 10 -30 5 -13 9 -25 9 -27
|
||||
0 -13 117 -257 164 -340 38 -68 98 -168 106 -175 3 -3 25 -34 50 -70 44 -66
|
||||
130 -177 185 -239 58 -67 170 -185 194 -205 14 -12 34 -30 45 -41 12 -12 50
|
||||
-45 86 -75 36 -30 67 -57 70 -60 3 -3 21 -17 40 -30 19 -13 37 -27 40 -30 10
|
||||
-11 136 -97 212 -144 l76 -47 0 -77 c-1 -131 22 -224 68 -287 30 -39 40 -68
|
||||
49 -135 4 -30 8 -64 10 -75 2 -11 6 -40 9 -65 3 -25 8 -55 10 -67 3 -12 7 -48
|
||||
11 -80 3 -32 8 -76 11 -98 3 -22 7 -56 9 -75 2 -19 6 -60 9 -90 8 -70 13 -119
|
||||
21 -200 4 -36 8 -81 11 -100 3 -19 7 -60 9 -90 2 -30 6 -75 9 -100 3 -25 8
|
||||
-76 11 -115 3 -38 8 -88 10 -110 2 -22 7 -78 11 -125 11 -132 15 -152 51 -223
|
||||
31 -62 84 -114 131 -127 24 -6 378 -10 1019 -10 976 0 983 0 1019 21 21 11 46
|
||||
31 56 45 11 13 26 31 34 39 9 8 12 15 8 15 -4 0 0 8 8 18 13 14 19 30 33 82 5
|
||||
22 16 109 20 175 3 44 8 94 10 110 2 17 7 60 10 95 11 137 16 186 20 225 3 22
|
||||
7 65 10 95 2 30 7 75 10 100 8 70 14 130 20 190 8 74 14 128 20 170 10 71 16
|
||||
118 20 160 2 24 7 61 10 84 24 164 35 209 60 246 52 76 66 128 72 270 3 84 7
|
||||
108 21 118 9 7 73 49 142 94 68 44 142 95 164 114 46 40 50 40 82 15 22 -18
|
||||
50 -20 142 -12 23 2 303 284 319 321 20 46 17 112 -6 151 l-20 32 35 46 c18
|
||||
25 37 51 42 56 52 68 192 286 192 301 0 2 11 22 25 44 14 22 23 40 19 40 -3 0
|
||||
4 13 15 29 12 16 21 32 21 35 0 5 17 45 70 161 21 48 108 303 114 336 3 13 5
|
||||
24 6 24 1 0 3 7 5 15 2 8 12 55 23 104 12 50 19 93 16 97 -2 4 0 10 6 14 6 4
|
||||
8 10 5 15 -11 17 20 23 119 23 55 0 113 4 128 9 57 20 58 28 58 485 -1 313 -4
|
||||
422 -13 434 -23 29 -66 51 -99 49 -98 -6 -195 1 -195 13 -2 85 -133 550 -164
|
||||
582 -5 5 -9 19 -9 32 0 13 -4 23 -10 23 -5 0 -10 6 -10 14 0 8 -6 27 -14 43
|
||||
-8 15 -20 42 -27 58 -8 17 -26 51 -41 78 -15 26 -26 47 -24 47 4 0 -78 142
|
||||
-104 180 -49 75 -60 92 -60 100 0 4 -3 10 -7 12 -5 2 -34 38 -66 81 -53 71
|
||||
-57 80 -44 95 14 16 34 76 32 97 -7 62 -24 86 -154 218 -138 141 -187 177
|
||||
-239 177 -35 0 -94 -19 -104 -34 -4 -6 -27 5 -60 27 -29 20 -87 60 -128 88
|
||||
-141 98 -158 109 -168 109 -23 0 -31 31 -33 124 -2 112 -22 191 -67 264 -38
|
||||
62 -46 89 -56 194 -2 19 -6 43 -9 54 -3 10 -9 50 -12 89 -4 38 -8 72 -10 75
|
||||
-1 3 -5 37 -9 75 -4 39 -8 81 -11 95 -2 14 -6 54 -9 90 -4 36 -8 76 -10 90 -2
|
||||
14 -7 57 -10 95 -4 39 -9 85 -11 103 -2 18 -7 65 -10 105 -3 40 -7 83 -9 97
|
||||
-3 14 -7 61 -10 105 -4 44 -8 91 -10 105 -3 14 -7 68 -11 120 -6 107 -13 156
|
||||
-24 185 -21 55 -57 118 -83 146 -60 62 -4 59 -1091 59 l-994 0 -41 -27z m1338
|
||||
-2207 c14 -4 48 -9 75 -12 28 -2 57 -7 65 -10 8 -3 35 -8 59 -10 23 -2 52 -9
|
||||
62 -15 10 -5 19 -8 19 -5 0 3 15 0 33 -5 17 -6 43 -12 57 -15 14 -3 52 -14 85
|
||||
-25 33 -11 67 -22 75 -24 53 -11 301 -119 390 -168 30 -17 69 -38 86 -48 46
|
||||
-26 208 -132 214 -141 3 -4 23 -19 45 -34 90 -61 331 -289 410 -389 22 -27 43
|
||||
-52 46 -55 26 -21 219 -310 219 -328 0 -6 4 -12 8 -14 25 -10 176 -355 217
|
||||
-493 9 -33 20 -67 23 -75 7 -20 9 -29 17 -69 3 -19 8 -37 10 -41 4 -7 10 -31
|
||||
30 -143 28 -152 36 -250 37 -442 0 -131 -2 -185 -17 -320 -4 -32 -13 -95 -21
|
||||
-132 -2 -13 -6 -35 -9 -50 -13 -69 -31 -151 -35 -158 -1 -3 -3 -8 -4 -12 -11
|
||||
-40 -30 -106 -43 -143 -8 -25 -16 -52 -18 -60 -13 -52 -144 -334 -198 -425
|
||||
-55 -93 -189 -288 -220 -320 -7 -7 -28 -32 -47 -56 -39 -49 -224 -235 -285
|
||||
-288 -169 -144 -528 -373 -567 -363 -5 1 -8 -3 -8 -8 0 -6 -4 -10 -10 -10 -5
|
||||
0 -33 -11 -62 -24 -128 -58 -380 -142 -453 -152 -11 -1 -56 -9 -100 -18 -179
|
||||
-35 -255 -41 -485 -40 -176 0 -289 6 -345 18 -11 2 -41 7 -67 10 -26 4 -69 11
|
||||
-95 16 -26 6 -59 13 -73 15 -14 3 -32 8 -40 11 -8 3 -26 8 -40 11 -32 6 -109
|
||||
29 -180 55 -30 11 -59 21 -65 22 -5 2 -21 8 -35 14 -14 6 -68 30 -120 52 -96
|
||||
42 -191 92 -265 139 -22 14 -42 26 -45 26 -3 0 -16 8 -30 18 -183 131 -191
|
||||
138 -269 202 -129 108 -337 337 -432 475 -24 35 -50 71 -57 78 -6 7 -12 17
|
||||
-12 22 0 5 -6 15 -13 22 -25 28 -154 276 -191 368 -10 25 -23 56 -29 70 -6 14
|
||||
-11 27 -12 30 -4 17 -48 148 -55 165 -19 46 -71 293 -85 410 -23 183 -24 487
|
||||
-1 640 3 22 8 56 10 75 29 234 133 551 262 799 53 103 166 287 204 334 5 7 42
|
||||
53 82 102 39 50 119 138 177 196 133 132 333 299 360 299 6 0 11 4 11 9 0 15
|
||||
185 123 340 198 81 39 254 110 285 118 6 1 17 5 25 8 18 7 91 30 105 33 201
|
||||
49 326 72 435 80 41 3 77 8 79 10 7 6 453 -3 481 -10z"/>
|
||||
<path d="M5703 6467 c-137 -211 -282 -432 -292 -444 -6 -7 -16 -24 -23 -38 -6
|
||||
-14 -14 -25 -18 -25 -4 0 -12 -11 -18 -25 -7 -14 -16 -31 -22 -38 -6 -7 -39
|
||||
-57 -75 -112 -36 -55 -69 -107 -75 -115 -5 -8 -48 -73 -94 -145 -47 -71 -90
|
||||
-135 -95 -142 -6 -7 -11 -17 -11 -23 0 -5 -4 -10 -10 -10 -5 0 -10 -4 -10 -9
|
||||
0 -5 -37 -64 -81 -131 l-81 -123 23 -18 c41 -31 72 -45 76 -34 3 10 84 134
|
||||
123 190 12 17 71 107 132 200 61 94 136 208 167 255 31 47 58 90 61 95 12 24
|
||||
66 100 73 103 4 2 7 7 7 12 0 4 36 62 80 129 44 66 79 124 78 127 -2 3 5 10
|
||||
15 15 9 6 17 15 17 20 0 6 20 39 45 75 25 35 45 68 45 73 0 5 3 11 8 13 4 2
|
||||
33 43 65 92 l57 89 -42 29 c-24 15 -45 28 -48 28 -3 0 -38 -51 -77 -113z"/>
|
||||
<path d="M4619 4871 c-67 -56 -33 -161 53 -161 56 0 98 42 93 94 -7 79 -88
|
||||
115 -146 67z"/>
|
||||
<path d="M5257 4523 c-73 -25 -152 -107 -173 -179 -26 -92 -10 -184 46 -250
|
||||
21 -25 92 -76 110 -80 3 0 21 -8 40 -16 19 -8 78 -32 130 -52 120 -46 152 -66
|
||||
188 -115 24 -33 29 -51 31 -105 5 -146 -85 -218 -267 -212 -104 4 -187 51
|
||||
-251 144 l-23 32 -28 -20 c-15 -11 -33 -20 -38 -20 -24 0 -21 -22 7 -62 89
|
||||
-129 205 -188 361 -182 92 3 110 7 168 36 100 48 161 126 178 228 12 75 4 133
|
||||
-28 196 -41 83 -104 124 -321 208 -133 52 -161 69 -189 123 -25 45 -20 132 9
|
||||
171 55 73 196 88 316 33 24 -11 50 -27 57 -36 18 -22 31 -19 68 16 l33 31 -23
|
||||
25 c-12 13 -55 40 -95 60 -65 32 -83 36 -165 39 -68 2 -106 -1 -141 -13z"/>
|
||||
<path d="M4626 4523 c-3 -4 -6 -357 -6 -785 l0 -779 38 2 c21 2 43 0 49 -4 6
|
||||
-4 14 0 17 8 8 23 7 1555 -1 1556 -47 6 -92 7 -97 2z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.8 KiB |
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "BangleApps",
|
||||
"short_name": "BangleApps",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#5755d9",
|
||||
"background_color": "#5755d9",
|
||||
"display": "standalone"
|
||||
}
|