From 98bad33895e93c35d719a848c9566a188f348da0 Mon Sep 17 00:00:00 2001 From: floppydiskette Date: Wed, 11 Dec 2024 23:05:59 +0000 Subject: [PATCH 1/2] Add today and yesterday pages --- css/wah.css | 41 +- images/logo.png | Bin 0 -> 22568 bytes includes/footer.inc.php | 12 + includes/head.inc.php | 14 + includes/header.inc.php | 19 + index.php | 346 +- js/menuSample.js | 2 +- js/setpagedata.js | 2 +- lib/steelseries/scripts/RGraph.rose.min.js | 2 +- lib/steelseries/scripts/gauges.js | 6915 ++++++++++---------- lib/steelseries/scripts/src/RGraph.rose.js | 1893 +++--- lib/steelseries/scripts/src/steelseries.js | 3548 +++++----- oldindex.htm | 242 - today.htm | 239 - today/index.php | 148 + yesterday.htm | 225 - yesterday/index.php | 149 + 17 files changed, 6713 insertions(+), 7084 deletions(-) create mode 100644 images/logo.png create mode 100644 includes/footer.inc.php create mode 100644 includes/head.inc.php create mode 100644 includes/header.inc.php delete mode 100644 oldindex.htm delete mode 100644 today.htm create mode 100644 today/index.php delete mode 100644 yesterday.htm create mode 100644 yesterday/index.php diff --git a/css/wah.css b/css/wah.css index 8de105d..950fc1a 100644 --- a/css/wah.css +++ b/css/wah.css @@ -94,6 +94,20 @@ div.page-container > div:last-child { margin-bottom: 0; } +div#header { + display: grid; + grid-template-columns: 66px 1fr; + grid-template-rows: 1fr; + grid-column-gap: 15px; + grid-row-gap: 0px; +} + +div#header img { + filter: drop-shadow(2px 2px hsl(0, 0%, 66%)); + margin-right: 10px; + image-rendering: pixelated; +} + div#header h1 { margin: 0; font-style: italic; @@ -118,8 +132,8 @@ div#footer { display: grid; grid-template-columns: auto 1fr; grid-template-rows: 1fr; - grid-column-gap: 0px; - grid-row-gap: 0px; + grid-column-gap: 0; + grid-row-gap: 0; align-items: center; } @@ -127,14 +141,6 @@ div#footer div:last-child { text-align: right; } -div#footer div:last-child img { - image-rendering: pixelated; - margin: 0; - padding: 0; - width: 88px; - height: 31px; -} - /* -------------------------------------------------------------------------- */ table.almanac td:nth-child(odd) { @@ -153,32 +159,33 @@ table.almanac { min-width: 100%; } -table.conditions-now { +table.mx-datatable { + width: 100%; border-collapse: collapse; border: var(--border); filter: var(--shadow-small); background-color: var(--background); } -table.conditions-now th { +table.mx-datatable th { text-align: left; background-color: var(--background-dim); border-top: var(--border); } -table.conditions-now tr td, -table.conditions-now tr th { +table.mx-datatable tr td, +table.mx-datatable tr th { padding: 5px 10px 5px 5px; } -table.conditions-now tr td:nth-child(2) { +table.mx-datatable tr td:nth-child(2) { padding-right: 40px; } -table.conditions-now tr td:nth-child(odd) { +table.current-conditions tr td:nth-child(odd) { font-weight: bold; } -table.conditions-now tr:last-child td:nth-child(3) { +table.current-conditions tr:last-child td:nth-child(3) { font-weight: normal; font-style: italic; } diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bbd099ba80f6d0d3eccf490789f2280ca66c13e8 GIT binary patch literal 22568 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 G+V@{ja}^>0 literal 0 HcmV?d00001 diff --git a/includes/footer.inc.php b/includes/footer.inc.php new file mode 100644 index 0000000..18d9835 --- /dev/null +++ b/includes/footer.inc.php @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/includes/head.inc.php b/includes/head.inc.php new file mode 100644 index 0000000..a2b1f32 --- /dev/null +++ b/includes/head.inc.php @@ -0,0 +1,14 @@ + + + + +Cumulus MX + + + + + + + + + diff --git a/includes/header.inc.php b/includes/header.inc.php new file mode 100644 index 0000000..c7787f9 --- /dev/null +++ b/includes/header.inc.php @@ -0,0 +1,19 @@ + diff --git a/index.php b/index.php index f62fb4f..3ce658a 100644 --- a/index.php +++ b/index.php @@ -2,198 +2,164 @@ - - - - - Cumulus MX - - - - - - - - - - + + -
- -
-

Almanac

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dawn:Sun Rise:Moon Rise:MoonVisible % -
Dusk:Sun Set:Moon Set:
Daylight:Day Length:Moon Phase:
-

-

Conditions at local time

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Temperature and Humidity
Temperature  - Dew Point  -
Windchill  - Humidity %
Heat Index Feels - Like  -
Temp change last hour 
Rainfall
Rainfall Today  - Rainfall Rate /hr -
Rainfall This Month  - Rainfall This Year  -
Rainfall Last Hour  - Last rainfall
Rainfall Since Midnight Rainfall Last 24 Hours  -
Wind
Wind Speed (gust)  - Wind Speed (avg)  -
Wind Bearing° - Beaufort
Wind Variation (last 10 minutes)From ° to °
Pressure (sea - level)
Barometer  -  /hr
-
- -
+
+ +
+

Almanac

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Dawn:Sun Rise:Moon Rise:MoonVisible + % +
Dusk:Sun Set:Moon Set:
Daylight:Day Length:Moon Phase:
+

+

Conditions at local time

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Temperature and Humidity
Temperature  + Dew Point  +
Windchill  + Humidity %
Heat Index Feels + Like  +
Temp change last hour  +
Rainfall
Rainfall Today  + Rainfall Rate /hr +
Rainfall This Month  + Rainfall This Year  +
Rainfall Last Hour  + Last rainfall
Rainfall Since Midnight Rainfall Last 24 Hours  +
Wind
Wind Speed (gust)  + Wind Speed (avg)  +
Wind Bearing° + Beaufort
Wind Variation (last 10 minutes)From ° to °
Pressure (sea + level)
Barometer  +  /hr +
+ Page data updated +
+ +
- + \ No newline at end of file diff --git a/js/menuSample.js b/js/menuSample.js index 87c644e..bdeff7f 100644 --- a/js/menuSample.js +++ b/js/menuSample.js @@ -38,7 +38,7 @@ menuSrc = [ { title: "Cumulus Forum", menu: "w", url: "#", forum: true, new_window: true }, { title: "Webcam", menu: "b", url: "#", webcam: true, new_window: true }, { title: "My Cat", menu: "b", url: "mycatpage.htm" }, - { title: "Some Cat", menu: "b", url: "https://pixnio.com/free-images/2020/07/26/2020-07-26-08-52-19-1200x1200.jpg", new_window: true } + { title: "Some Cat", menu: "b", url: "https://pixnio.com/free-/images/2020/07/26/2020-07-26-08-52-19-1200x1200.jpg", new_window: true } ] } ]; diff --git a/js/setpagedata.js b/js/setpagedata.js index 999a118..56d567d 100644 --- a/js/setpagedata.js +++ b/js/setpagedata.js @@ -14,7 +14,7 @@ let fixedHeader = false; // Use only true or false let fixedFooter = true; // Use only true or false let headerMargin = 20; // Gap between the header and the main body let footerMargin = 10; // Gap between the body and the footer -let load_menu = "js/menu.js"; // menu file to load - path is relative to the page +let load_menu = "/js/menu.js"; // menu file to load - path is relative to the page // Thats the only changes you should make unless you know better! diff --git a/lib/steelseries/scripts/RGraph.rose.min.js b/lib/steelseries/scripts/RGraph.rose.min.js index 4e21f88..1038289 100644 --- a/lib/steelseries/scripts/RGraph.rose.min.js +++ b/lib/steelseries/scripts/RGraph.rose.min.js @@ -1 +1 @@ -typeof RGraph=="undefined"&&(RGraph={}),RGraph.Rose=function(n,t){var r,i;for(this.id=n,this.canvas=document.getElementById(n),this.context=this.canvas.getContext("2d"),this.data=t,this.canvas.__object__=this,this.type="rose",this.isRGraph=!0,this.uid=RGraph.CreateUID(),this.canvas.uid=this.canvas.uid?this.canvas.uid:RGraph.CreateUID(),this.colorsParsed=!1,RGraph.OldBrowserCompat(this.context),this.centerx=0,this.centery=0,this.radius=0,this.max=0,this.angles=[],this.properties={"chart.background.axes":!0,"chart.background.axes.color":"black","chart.background.grid":!0,"chart.background.grid.color":"#ccc","chart.background.grid.size":null,"chart.background.grid.spokes":null,"chart.background.grid.count":5,"chart.centerx":null,"chart.centery":null,"chart.radius":null,"chart.colors":["rgba(255,0,0,0.5)","rgba(255,255,0,0.5)","rgba(0,255,255,0.5)","rgb(0,255,0)","gray","blue","rgb(255,128,255)","green","pink","gray","aqua"],"chart.colors.sequential":!1,"chart.colors.alpha":null,"chart.margin":0,"chart.strokestyle":"#aaa","chart.gutter.left":25,"chart.gutter.right":25,"chart.gutter.top":25,"chart.gutter.bottom":25,"chart.title":"","chart.title.background":null,"chart.title.hpos":null,"chart.title.vpos":null,"chart.title.bold":!0,"chart.title.font":null,"chart.title.x":null,"chart.title.y":null,"chart.title.halign":null,"chart.title.valign":null,"chart.labels":null,"chart.labels.position":"center","chart.labels.axes":"nsew","chart.labels.offset":0,"chart.text.color":"black","chart.text.font":"Arial","chart.text.size":10,"chart.key":null,"chart.key.background":"white","chart.key.position":"graph","chart.key.halign":"right","chart.key.shadow":!1,"chart.key.shadow.color":"#666","chart.key.shadow.blur":3,"chart.key.shadow.offsetx":2,"chart.key.shadow.offsety":2,"chart.key.position.gutter.boxed":!0,"chart.key.position.x":null,"chart.key.position.y":null,"chart.key.color.shape":"square","chart.key.rounded":!0,"chart.key.linewidth":1,"chart.key.colors":null,"chart.contextmenu":null,"chart.tooltips":null,"chart.tooltips.event":"onclick","chart.tooltips.effect":"fade","chart.tooltips.css.class":"RGraph_tooltip","chart.tooltips.highlight":!0,"chart.highlight.stroke":"rgba(0,0,0,0)","chart.highlight.fill":"rgba(255,255,255,0.7)","chart.annotatable":!1,"chart.annotate.color":"black","chart.zoom.factor":1.5,"chart.zoom.fade.in":!0,"chart.zoom.fade.out":!0,"chart.zoom.hdir":"right","chart.zoom.vdir":"down","chart.zoom.frames":25,"chart.zoom.delay":16.666,"chart.zoom.shadow":!0,"chart.zoom.background":!0,"chart.zoom.action":"zoom","chart.resizable":!1,"chart.resize.handle.adjust":[0,0],"chart.resize.handle.background":null,"chart.adjustable":!1,"chart.ymax":null,"chart.ymin":0,"chart.scale.decimals":null,"chart.scale.point":".","chart.scale.thousand":",","chart.variant":"stacked","chart.exploded":0,"chart.events.mousemove":null,"chart.events.click":null,"chart.animation.roundrobin.factor":1,"chart.animation.roundrobin.radius":!0,"chart.animation.grow.multiplier":1},r=RGraph.array_linearize(this.data),i=0;i0&&this.Get("chart.key").length>=3&&(this.centerx=this.centerx-this.Get("chart.gutter.right")+5),typeof this.Get("chart.centerx")=="number"&&(this.centerx=this.Get("chart.centerx")),typeof this.Get("chart.centery")=="number"&&(this.centery=this.Get("chart.centery")),typeof this.Get("chart.radius")=="number"&&(this.radius=this.Get("chart.radius")),this.colorsParsed||(this.parseColors(),this.colorsParsed=!0),this.DrawBackground(),this.DrawRose(),this.DrawLabels(),this.Get("chart.contextmenu")&&RGraph.ShowContext(this),this.Get("chart.resizable")&&RGraph.AllowResizing(this),this.Get("chart.adjustable")&&RGraph.AllowAdjusting(this),RGraph.InstallEventListeners(this),RGraph.FireCustomEvent(this,"ondraw")},RGraph.Rose.prototype.DrawBackground=function(){var t,n;if(this.context.lineWidth=1,this.properties["chart.background.grid"]){for(typeof this.properties["chart.background.grid.count"]=="number"&&(this.properties["chart.background.grid.size"]=this.radius/this.properties["chart.background.grid.count"]),this.context.beginPath(),this.context.strokeStyle=this.properties["chart.background.grid.color"],n=this.properties["chart.background.grid.size"];n<=this.radius;n+=this.properties["chart.background.grid.size"])this.context.arc(this.centerx,this.centery,n,0,TWOPI,!1);if(this.context.stroke(),this.context.beginPath(),typeof this.properties["chart.background.grid.spokes"]=="number")for(t=360/this.properties["chart.background.grid.spokes"],n=t;n<=360;n+=t)this.context.arc(this.centerx,this.centery,this.radius,n/(180/PI)-HALFPI,(n+.0001)/(180/PI)-HALFPI,0),this.context.lineTo(this.centerx,this.centery);else for(n=15;n<=360;n+=15)this.context.arc(this.centerx,this.centery,this.radius,n/(180/PI)-HALFPI,(n+.0001)/(180/PI)-HALFPI,!1),this.context.lineTo(this.centerx,this.centery);this.context.stroke()}if(this.Get("chart.background.axes")){for(this.context.beginPath(),this.context.strokeStyle=this.Get("chart.background.axes.color"),this.context.moveTo(this.centerx-this.radius,Math.round(this.centery)),this.context.lineTo(this.centerx+this.radius,Math.round(this.centery)),this.context.moveTo(Math.round(this.centerx-this.radius),this.centery-5),this.context.lineTo(Math.round(this.centerx-this.radius),this.centery+5),this.context.moveTo(Math.round(this.centerx+this.radius),this.centery-5),this.context.lineTo(Math.round(this.centerx+this.radius),this.centery+5),n=this.centerx-this.radius;n-1&&(RGraph.Text(i,t,n,this.centerx,this.centery-u*.2,RGraph.number_format(this,Number(this.scale[0]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery-u*.4,RGraph.number_format(this,Number(this.scale[1]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery-u*.6,RGraph.number_format(this,Number(this.scale[2]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery-u*.8,RGraph.number_format(this,Number(this.scale[3]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery-u,RGraph.number_format(this,Number(this.scale[4]).toFixed(o),f,e),"center","center",!0,!1,r)),s.indexOf("s")>-1&&(RGraph.Text(i,t,n,this.centerx,this.centery+u*.2,RGraph.number_format(this,Number(this.scale[0]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery+u*.4,RGraph.number_format(this,Number(this.scale[1]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery+u*.6,RGraph.number_format(this,Number(this.scale[2]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery+u*.8,RGraph.number_format(this,Number(this.scale[3]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx,this.centery+u,RGraph.number_format(this,Number(this.scale[4]).toFixed(o),f,e),"center","center",!0,!1,r)),s.indexOf("e")>-1&&(RGraph.Text(i,t,n,this.centerx+u*.2,this.centery,RGraph.number_format(this,Number(this.scale[0]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx+u*.4,this.centery,RGraph.number_format(this,Number(this.scale[1]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx+u*.6,this.centery,RGraph.number_format(this,Number(this.scale[2]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx+u*.8,this.centery,RGraph.number_format(this,Number(this.scale[3]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx+u,this.centery,RGraph.number_format(this,Number(this.scale[4]).toFixed(o),f,e),"center","center",!0,!1,r)),s.indexOf("w")>-1&&(RGraph.Text(i,t,n,this.centerx-u*.2,this.centery,RGraph.number_format(this,Number(this.scale[0]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx-u*.4,this.centery,RGraph.number_format(this,Number(this.scale[1]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx-u*.6,this.centery,RGraph.number_format(this,Number(this.scale[2]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx-u*.8,this.centery,RGraph.number_format(this,Number(this.scale[3]).toFixed(o),f,e),"center","center",!0,!1,r),RGraph.Text(i,t,n,this.centerx-u,this.centery,RGraph.number_format(this,Number(this.scale[4]).toFixed(o),f,e),"center","center",!0,!1,r)),s.length>0&&RGraph.Text(i,t,n,this.centerx,this.centery,typeof this.Get("chart.ymin")=="number"?RGraph.number_format(this,Number(this.Get("chart.ymin")).toFixed(this.Get("chart.scale.decimals")),f,e):"0","center","center",!0,!1,r)},RGraph.Rose.prototype.DrawCircularLabels=function(n,t,i,r,u){for(var s=this.Get("chart.variant"),c=this.Get("chart.labels.position"),u=u+5+this.Get("chart.labels.offset"),e,o,h,f=0;fthis.centerx?"left":o==this.centerx?"center":"right",RGraph.Text(n,i,r,o,h,String(t[f]),"center",halign)},RGraph.Rose.prototype.getShape=RGraph.Rose.prototype.getSegment=function(n){var t,e;RGraph.FixEventObject(n);var a=this.canvas,c=this.context,i=this.angles;for(t=0;t0?this.context.arc(n.x,n.y,n["radius.start"],n["angle.end"],n["angle.start"],!0):this.context.lineTo(n.x,n.y),this.context.closePath(),this.context.stroke(),this.context.fill())},RGraph.Rose.prototype.getObjectByXY=function(n){var t=RGraph.getMouseXY(n),i=RGraph.getHypLength(this.centerx,this.centery,t[0],t[1]);if(t[0]>this.centerx-this.radius&&t[0]this.centery-this.radius&&t[1]document.body.offsetWidth-10?(r.style.left=s[0]+c+Math.cos(o)*e-h*.9+"px",r.style.top=s[1]+l+Math.sin(o)*e-a-5+"px",f.style.left=h*.9-8.5+"px"):(r.style.left=s[0]+c+Math.cos(o)*e-h/2+"px",r.style.top=s[1]+l+Math.sin(o)*e-a-5+"px",f.style.left=h*.5-8.5+"px")},RGraph.Rose.prototype.getRadius=function(n){if(n<0||n>this.max)return null;return n/this.max*this.radius},RGraph.Rose.prototype.parseColors=function(){for(var n=0;n 0 && this.Get("chart.key").length >= 3 && (this.centerx = this.centerx - this.Get("chart.gutter.right") + 5), typeof this.Get("chart.centerx") == "number" && (this.centerx = this.Get("chart.centerx")), typeof this.Get("chart.centery") == "number" && (this.centery = this.Get("chart.centery")), typeof this.Get("chart.radius") == "number" && (this.radius = this.Get("chart.radius")), this.colorsParsed || (this.parseColors(), this.colorsParsed = !0), this.DrawBackground(), this.DrawRose(), this.DrawLabels(), this.Get("chart.contextmenu") && RGraph.ShowContext(this), this.Get("chart.resizable") && RGraph.AllowResizing(this), this.Get("chart.adjustable") && RGraph.AllowAdjusting(this), RGraph.InstallEventListeners(this), RGraph.FireCustomEvent(this, "ondraw") }, RGraph.Rose.prototype.DrawBackground = function () { var t, n; if (this.context.lineWidth = 1, this.properties["chart.background.grid"]) { for (typeof this.properties["chart.background.grid.count"] == "number" && (this.properties["chart.background.grid.size"] = this.radius / this.properties["chart.background.grid.count"]), this.context.beginPath(), this.context.strokeStyle = this.properties["chart.background.grid.color"], n = this.properties["chart.background.grid.size"]; n <= this.radius; n += this.properties["chart.background.grid.size"])this.context.arc(this.centerx, this.centery, n, 0, TWOPI, !1); if (this.context.stroke(), this.context.beginPath(), typeof this.properties["chart.background.grid.spokes"] == "number") for (t = 360 / this.properties["chart.background.grid.spokes"], n = t; n <= 360; n += t)this.context.arc(this.centerx, this.centery, this.radius, n / (180 / PI) - HALFPI, (n + .0001) / (180 / PI) - HALFPI, 0), this.context.lineTo(this.centerx, this.centery); else for (n = 15; n <= 360; n += 15)this.context.arc(this.centerx, this.centery, this.radius, n / (180 / PI) - HALFPI, (n + .0001) / (180 / PI) - HALFPI, !1), this.context.lineTo(this.centerx, this.centery); this.context.stroke() } if (this.Get("chart.background.axes")) { for (this.context.beginPath(), this.context.strokeStyle = this.Get("chart.background.axes.color"), this.context.moveTo(this.centerx - this.radius, Math.round(this.centery)), this.context.lineTo(this.centerx + this.radius, Math.round(this.centery)), this.context.moveTo(Math.round(this.centerx - this.radius), this.centery - 5), this.context.lineTo(Math.round(this.centerx - this.radius), this.centery + 5), this.context.moveTo(Math.round(this.centerx + this.radius), this.centery - 5), this.context.lineTo(Math.round(this.centerx + this.radius), this.centery + 5), n = this.centerx - this.radius; n < this.centerx + this.radius; n += this.radius / 5)this.context.moveTo(Math.round(n), this.centery - 3), this.context.lineTo(Math.round(n), this.centery + 3.5); for (n = this.centery - this.radius; n < this.centery + this.radius; n += this.radius / 5)this.context.moveTo(this.centerx - 3, Math.round(n)), this.context.lineTo(this.centerx + 3, Math.round(n)); this.context.moveTo(Math.round(this.centerx), this.centery - this.radius), this.context.lineTo(Math.round(this.centerx), this.centery + this.radius), this.context.moveTo(this.centerx - 5, Math.round(this.centery - this.radius)), this.context.lineTo(this.centerx + 5, Math.round(this.centery - this.radius)), this.context.moveTo(this.centerx - 5, Math.round(this.centery + this.radius)), this.context.lineTo(this.centerx + 5, Math.round(this.centery + this.radius)), this.context.closePath(), this.context.stroke() } }, RGraph.Rose.prototype.DrawRose = function () { var p = 0, h = this.data, c = RGraph.degrees2Radians(this.Get("chart.margin")), v, s, w, b, n, o, f, a, y, e; if (this.Get("chart.ymax")) v = this.Get("chart.ymax"), s = this.Get("chart.ymin"), this.scale = [(v - s) * .2 + s, (v - s) * .4 + s, (v - s) * .6 + s, (v - s) * .8 + s, (v - s) * 1 + s], this.max = this.scale[4]; else { for (n = 0; n < h.length; ++n)p = typeof h[n] == "number" ? Math.max(p, h[n]) : typeof h[n] == "object" && this.Get("chart.variant") == "non-equi-angular" ? Math.max(p, h[n][0]) : Math.max(p, RGraph.array_sum(h[n])); this.scale = RGraph.getScale(p, this), this.max = this.scale[4] } if (this.sum = RGraph.array_sum(h), this.context.moveTo(this.centerx, this.centery), this.context.stroke(), this.Get("chart.colors.alpha") && (this.context.globalAlpha = this.Get("chart.colors.alpha")), typeof this.Get("chart.variant") == "string" && this.Get("chart.variant") == "non-equi-angular") { for (w = 0, n = 0; n < h.length; ++n)w += h[n][1]; for (n = 0; n < this.data.length; ++n) { o = this.data[n][1] / w * TWOPI, f = (this.data[n][0] - this.Get("chart.ymin")) / (this.max - this.Get("chart.ymin")) * this.radius, f = f * this.properties["chart.animation.grow.multiplier"], this.context.strokeStyle = this.Get("chart.strokestyle"), this.context.fillStyle = this.Get("chart.colors")[0], this.Get("chart.colors.sequential") && (this.context.fillStyle = this.Get("chart.colors")[n]), this.context.beginPath(); var i = this.startRadians * this.Get("chart.animation.roundrobin.factor") - HALFPI + c - o / 2, t = (this.startRadians + o) * this.Get("chart.animation.roundrobin.factor") - HALFPI - c - o / 2, l = this.getexploded(n, i, t, this.Get("chart.exploded")), r = l[0], u = l[1]; this.context.arc(this.centerx + r, this.centery + u, this.Get("chart.animation.roundrobin.radius") ? f * this.Get("chart.animation.roundrobin.factor") : f, i, t, 0), this.context.lineTo(this.centerx + r, this.centery + u), this.context.closePath(), this.context.stroke(), this.context.fill(), this.angles.push(gg = [i, t, 0, f, this.centerx + r, this.centery + u]), this.startRadians += o } } else for (b = 0, n = 0; n < this.data.length; ++n) { if (this.context.strokeStyle = this.Get("chart.strokestyle"), this.context.fillStyle = this.Get("chart.colors")[0], this.Get("chart.colors.sequential") && (this.context.fillStyle = this.Get("chart.colors")[n]), o = 1 / this.data.length * TWOPI, typeof this.data[n] == "number") { this.context.beginPath(), f = (this.data[n] - this.Get("chart.ymin")) / (this.max - this.Get("chart.ymin")) * this.radius, f = f * this.properties["chart.animation.grow.multiplier"]; var i = this.startRadians * this.Get("chart.animation.roundrobin.factor") - HALFPI + c - o / 2, t = this.startRadians * this.Get("chart.animation.roundrobin.factor") + o * this.Get("chart.animation.roundrobin.factor") - HALFPI - c - o / 2, l = this.getexploded(n, i, t, this.Get("chart.exploded")), r = l[0], u = l[1]; this.context.arc(this.centerx + r, this.centery + u, this.Get("chart.animation.roundrobin.radius") ? f * this.Get("chart.animation.roundrobin.factor") : f, i, t, 0), this.context.lineTo(this.centerx + r, this.centery + u), this.context.closePath(), this.context.stroke(), this.context.fill(), t == 0, this.angles.push([i, t, 0, f * this.Get("chart.animation.roundrobin.factor"), this.centerx + r, this.centery + u]) } else if (typeof this.data[n] == "object") for (c = this.Get("chart.margin") / (180 / PI), a = 0; a < this.data[n].length; ++a) { var i = this.startRadians * this.Get("chart.animation.roundrobin.factor") - HALFPI + c, t = this.startRadians * this.Get("chart.animation.roundrobin.factor") + o * this.Get("chart.animation.roundrobin.factor") - HALFPI - c, l = this.getexploded(n, i, t, this.Get("chart.exploded")), r = l[0], u = l[1]; this.context.fillStyle = this.Get("chart.colors")[a], this.Get("chart.colors.sequential") && (this.context.fillStyle = this.Get("chart.colors")[b++]), a == 0 ? (this.context.beginPath(), y = 0, e = (this.data[n][a] - this.Get("chart.ymin")) / (this.max - this.Get("chart.ymin")) * this.radius, e = e * this.properties["chart.animation.grow.multiplier"], this.context.arc(this.centerx + r, this.centery + u, this.Get("chart.animation.roundrobin.radius") ? e * this.Get("chart.animation.roundrobin.factor") : e, i, t, 0), this.context.lineTo(this.centerx + r, this.centery + u), this.context.closePath(), this.context.stroke(), this.context.fill(), this.angles.push([i, t, 0, e * this.Get("chart.animation.roundrobin.factor"), this.centerx + r, this.centery + u])) : (this.context.beginPath(), y = e, e = (this.data[n][a] - this.Get("chart.ymin")) / (this.max - this.Get("chart.ymin")) * this.radius + y, e = e * this.properties["chart.animation.grow.multiplier"], this.context.arc(this.centerx + r, this.centery + u, y * this.Get("chart.animation.roundrobin.factor"), i, t, 0), this.context.arc(this.centerx + r, this.centery + u, e * this.Get("chart.animation.roundrobin.factor"), t, i, !0), this.context.closePath(), this.context.stroke(), this.context.fill(), this.angles.push([i, t, y * this.Get("chart.animation.roundrobin.factor"), e * this.Get("chart.animation.roundrobin.factor"), this.centerx + r, this.centery + u])) } this.startRadians += o } this.Get("chart.colors.alpha") && (this.context.globalAlpha = 1), this.Get("chart.title") && RGraph.DrawTitle(this, this.Get("chart.title"), this.canvas.height / 2 - this.radius, this.centerx, this.Get("chart.title.size") ? this.Get("chart.title.size") : this.Get("chart.text.size") + 2) }, RGraph.Rose.prototype.DrawLabels = function () { var h, r; this.context.lineWidth = 1, h = this.Get("chart.key"), h && h.length && RGraph.DrawKey(this, h, this.Get("chart.colors")), this.context.fillStyle = this.properties["chart.text.color"], this.context.strokeStyle = "black"; var u = this.radius, t = this.Get("chart.text.font"), n = this.Get("chart.text.size"), i = this.context, s = this.Get("chart.labels.axes").toLowerCase(), o = this.Get("chart.scale.decimals"), f = this.Get("chart.units.pre"), e = this.Get("chart.units.post"); typeof this.Get("chart.labels") == "object" && this.Get("chart.labels") && this.DrawCircularLabels(i, this.Get("chart.labels"), t, n, u + 10), typeof this.properties["chart.text.size.scale"] == "number" && (n = this.properties["chart.text.size.scale"]), r = "rgba(255,255,255,0.8)", s.indexOf("n") > -1 && (RGraph.Text(i, t, n, this.centerx, this.centery - u * .2, RGraph.number_format(this, Number(this.scale[0]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery - u * .4, RGraph.number_format(this, Number(this.scale[1]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery - u * .6, RGraph.number_format(this, Number(this.scale[2]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery - u * .8, RGraph.number_format(this, Number(this.scale[3]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery - u, RGraph.number_format(this, Number(this.scale[4]).toFixed(o), f, e), "center", "center", !0, !1, r)), s.indexOf("s") > -1 && (RGraph.Text(i, t, n, this.centerx, this.centery + u * .2, RGraph.number_format(this, Number(this.scale[0]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery + u * .4, RGraph.number_format(this, Number(this.scale[1]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery + u * .6, RGraph.number_format(this, Number(this.scale[2]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery + u * .8, RGraph.number_format(this, Number(this.scale[3]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx, this.centery + u, RGraph.number_format(this, Number(this.scale[4]).toFixed(o), f, e), "center", "center", !0, !1, r)), s.indexOf("e") > -1 && (RGraph.Text(i, t, n, this.centerx + u * .2, this.centery, RGraph.number_format(this, Number(this.scale[0]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx + u * .4, this.centery, RGraph.number_format(this, Number(this.scale[1]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx + u * .6, this.centery, RGraph.number_format(this, Number(this.scale[2]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx + u * .8, this.centery, RGraph.number_format(this, Number(this.scale[3]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx + u, this.centery, RGraph.number_format(this, Number(this.scale[4]).toFixed(o), f, e), "center", "center", !0, !1, r)), s.indexOf("w") > -1 && (RGraph.Text(i, t, n, this.centerx - u * .2, this.centery, RGraph.number_format(this, Number(this.scale[0]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx - u * .4, this.centery, RGraph.number_format(this, Number(this.scale[1]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx - u * .6, this.centery, RGraph.number_format(this, Number(this.scale[2]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx - u * .8, this.centery, RGraph.number_format(this, Number(this.scale[3]).toFixed(o), f, e), "center", "center", !0, !1, r), RGraph.Text(i, t, n, this.centerx - u, this.centery, RGraph.number_format(this, Number(this.scale[4]).toFixed(o), f, e), "center", "center", !0, !1, r)), s.length > 0 && RGraph.Text(i, t, n, this.centerx, this.centery, typeof this.Get("chart.ymin") == "number" ? RGraph.number_format(this, Number(this.Get("chart.ymin")).toFixed(this.Get("chart.scale.decimals")), f, e) : "0", "center", "center", !0, !1, r) }, RGraph.Rose.prototype.DrawCircularLabels = function (n, t, i, r, u) { for (var s = this.Get("chart.variant"), c = this.Get("chart.labels.position"), u = u + 5 + this.Get("chart.labels.offset"), e, o, h, f = 0; f < this.angles.length; ++f)typeof s == "string" && s == "non-equi-angular" ? e = Number(this.angles[f][0]) + (this.angles[f][1] - this.angles[f][0]) / 2 : (e = TWOPI / t.length * (f + 1) - TWOPI / (t.length * 2), e = e - HALFPI + (this.Get("chart.labels.position") == "edge" ? TWOPI / t.length / 2 : 0)), o = this.centerx + Math.cos(e) * u, h = this.centery + Math.sin(e) * u, halign = o > this.centerx ? "left" : o == this.centerx ? "center" : "right", RGraph.Text(n, i, r, o, h, String(t[f]), "center", halign) }, RGraph.Rose.prototype.getShape = RGraph.Rose.prototype.getSegment = function (n) { var t, e; RGraph.FixEventObject(n); var a = this.canvas, c = this.context, i = this.angles; for (t = 0; t < i.length; ++t) { var o = i[t][0], s = i[t][1], h = i[t][2], l = i[t][3], u = i[t][4], f = i[t][5], r = RGraph.getMouseXY(n), v = r[0] - u, y = r[1] - f; if (this.context.beginPath(), this.context.arc(u, f, h ? h : .01, o, s, !1), this.context.arc(u, f, l, s, o, !0), this.context.closePath(), c.isPointInPath(r[0], r[1])) return i[t][6] = t, RGraph.parseTooltipText && (e = RGraph.parseTooltipText(this.Get("chart.tooltips"), i[t][6])), i[t].object = this, i[t].x = i[t][4], i[t].y = i[t][5], i[t]["angle.start"] = i[t][0], i[t]["angle.end"] = i[t][1], i[t]["radius.start"] = i[t][2], i[t]["radius.end"] = i[t][3], i[t].index = i[t][6], i[t].tooltip = e ? e : null, i[t] } return null }, RGraph.Rose.prototype.getexploded = function (n, t, i, r) { var u, f; return typeof r == "object" && typeof r[n] == "number" ? (u = Math.cos((i - t) / 2 + t) * r[n], f = Math.sin((i - t) / 2 + t) * r[n]) : typeof r == "number" ? (u = Math.cos((i - t) / 2 + t) * r, f = Math.sin((i - t) / 2 + t) * r) : (u = 0, f = 0), [u, f] }, RGraph.Rose.prototype.AllowTooltips = function () { RGraph.PreLoadTooltip / images(this), RGraph.InstallWindowMousedownTooltipListener(this), RGraph.InstallCanvasMousemoveTooltipListener(this), RGraph.InstallCanvasMouseupTooltipListener(this) }, RGraph.Rose.prototype.Highlight = function (n) { this.Get("chart.tooltips.highlight") && (this.context.beginPath(), this.context.strokeStyle = this.Get("chart.highlight.stroke"), this.context.fillStyle = this.Get("chart.highlight.fill"), this.context.arc(n.x, n.y, n["radius.end"], n["angle.start"], n["angle.end"], !1), n["radius.start"] > 0 ? this.context.arc(n.x, n.y, n["radius.start"], n["angle.end"], n["angle.start"], !0) : this.context.lineTo(n.x, n.y), this.context.closePath(), this.context.stroke(), this.context.fill()) }, RGraph.Rose.prototype.getObjectByXY = function (n) { var t = RGraph.getMouseXY(n), i = RGraph.getHypLength(this.centerx, this.centery, t[0], t[1]); if (t[0] > this.centerx - this.radius && t[0] < this.centerx + this.radius && t[1] > this.centery - this.radius && t[1] < this.centery + this.radius && i <= this.radius) return this }, RGraph.Rose.prototype.positionTooltip = function (n, t, i, r, u) { var c = n.angles[u][4], l = n.angles[u][5], v = n.angles[u][0], y = n.angles[u][1], e = (n.angles[u][3] - n.angles[u][2]) / 2 + n.angles[u][2], o = (y - v) / 2 + v, s = RGraph.getCanvasXY(n.canvas), p = n.Get("chart.gutter.left"), w = n.Get("chart.gutter.top"), h = r.offsetWidth, a = r.offsetHeight, f; r.style.overflow = "", f = new Image, f.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC", f.style.position = "absolute", f.id = "__rgraph_tooltip_pointer__", f.style.top = r.offsetHeight - 2 + "px", r.appendChild(f), s[0] + c + Math.cos(o) * e - h / 2 < 10 ? (r.style.left = s[0] + c + Math.cos(o) * e - h * .1 + "px", r.style.top = s[1] + l + Math.sin(o) * e - a - 5 + "px", f.style.left = h * .1 - 8.5 + "px") : s[0] + c + Math.cos(o) * e + h / 2 > document.body.offsetWidth - 10 ? (r.style.left = s[0] + c + Math.cos(o) * e - h * .9 + "px", r.style.top = s[1] + l + Math.sin(o) * e - a - 5 + "px", f.style.left = h * .9 - 8.5 + "px") : (r.style.left = s[0] + c + Math.cos(o) * e - h / 2 + "px", r.style.top = s[1] + l + Math.sin(o) * e - a - 5 + "px", f.style.left = h * .5 - 8.5 + "px") }, RGraph.Rose.prototype.getRadius = function (n) { if (n < 0 || n > this.max) return null; return n / this.max * this.radius }, RGraph.Rose.prototype.parseColors = function () { for (var n = 0; n < this.properties["chart.colors"].length; ++n)this.properties["chart.colors"][n] = this.parseSingleColorForGradient(this.properties["chart.colors"][n]); if (!RGraph.is_null(this.properties["chart.key.colors"])) for (n = 0; n < this.properties["chart.key.colors"].length; ++n)this.properties["chart.key.colors"][n] = this.parseSingleColorForGradient(this.properties["chart.key.colors"][n]); this.properties["chart.text.color"] = this.parseSingleColorForGradient(this.properties["chart.text.color"]), this.properties["chart.title.color"] = this.parseSingleColorForGradient(this.properties["chart.title.color"]), this.properties["chart.highlight.fill"] = this.parseSingleColorForGradient(this.properties["chart.highlight.fill"]), this.properties["chart.highlight.stroke"] = this.parseSingleColorForGradient(this.properties["chart.highlight.stroke"]) }, RGraph.Rose.prototype.parseSingleColorForGradient = function (n) { var e = this.canvas, u = this.context, t; if (!n || typeof n != "string") return n; if (n.match(/^gradient\((.*)\)$/i)) { var i = RegExp.$1.split(":"), r = u.createRadialGradient(this.centerx, this.centery, 0, this.centerx, this.centery, this.radius), f = 1 / (i.length - 1); for (r.addColorStop(0, RGraph.trim(i[0])), t = 1; t < i.length; ++t)r.addColorStop(t * f, RGraph.trim(i[t])) } return r ? r : n } diff --git a/lib/steelseries/scripts/gauges.js b/lib/steelseries/scripts/gauges.js index 5caf9ad..38f1994 100644 --- a/lib/steelseries/scripts/gauges.js +++ b/lib/steelseries/scripts/gauges.js @@ -25,9 +25,9 @@ (function ($) { 'use strict'; var o = $({}); - $.subscribe = function () {o.on.apply(o, arguments);}; - $.unsubscribe = function () {o.off.apply(o, arguments);}; - $.publish = function () {o.trigger.apply(o, arguments);}; + $.subscribe = function () { o.on.apply(o, arguments); }; + $.unsubscribe = function () { o.off.apply(o, arguments); }; + $.publish = function () { o.trigger.apply(o, arguments); }; }(jQuery)); var gauges; @@ -36,186 +36,186 @@ gauges = (function () { var strings = LANG.EN, // Set to your default language. Store all the strings in one object config = { // Script configuration parameters you may want to 'tweak' - scriptVer : '2.7.7', - weatherProgram : 0, // Set 0=Cumulus, 1=Weather Display, 2=VWS, 3=WeatherCat, 4=Meteobridge, 5=WView, 6=WeeWX, 7=WLCOM - imgPathURL : './images/', // *** Change this to the relative path for your 'Trend' graph images - oldGauges : 'gauges.htm', // *** Change this to the relative path for your 'old' gauges page. - realtimeInterval : 15, // *** Download data interval, set to your realtime data update interval in seconds - longPoll : false, // if enabled, use long polling and PHP generated data !!only enable if you understand how this is implemented!! - gaugeMobileScaling : 0.85, // scaling factor to apply when displaying the gauges mobile devices, set to 1 to disable (default 0.85) - graphUpdateTime : 15, // period of pop-up data graph refresh, in minutes (default 15) - stationTimeout : 3, // period of no data change before we declare the station off-line, in minutes (default 3) - pageUpdateLimit : 20, // period after which the page stops automatically updating, in minutes (default 20), - // - set to 0 (zero) to disable this feature - pageUpdatePswd : 'its-me', // password to over ride the page updates time-out, do not set to blank even if you do not use a password - http://&pageUpdate=its-me - digitalFont : false, // Font control for the gauges & timer - digitalForecast : false, // Font control for the status display, set this to false for languages that use accented characters in the forecasts - showPopupData : true, // Pop-up data displayed - showPopupGraphs : false, // If pop-up data is displayed, show the graphs? - mobileShowGraphs : false, // If false, on a mobile/narrow display, always disable the graphs - showWindVariation : true, // Show variation in wind direction over the last 10 minutes on the direction gauge - showWindMetar : false, // Show the METAR substring for wind speed/direction over the last 10 minutes on the direction gauge popup - showIndoorTempHum : true, // Show the indoor temperature/humidity options - showCloudGauge : true, // Display the Cloud Base gauge - showUvGauge : true, // Display the UV Index gauge - showSolarGauge : true, // Display the Solar gauge - showSunshineLed : true, // Show 'sun shining now' LED on solar gauge - showRoseGauge : true, // Show the optional Wind Rose gauge - showRoseGaugeOdo : true, // Show the optional Wind Rose gauge wind run Odometer - showRoseOnDirGauge : true, // Show the rose data as sectors on the direction gauge - showGaugeShadow : true, // Show a drop shadow outside the gauges - roundCloudbaseVal : true, // Round the value shown on the cloud base gauge to make it easier to read - // The realtime files should be absolute paths, "/xxx.txt" refers to the public root of your web server + scriptVer: '2.7.7', + weatherProgram: 0, // Set 0=Cumulus, 1=Weather Display, 2=VWS, 3=WeatherCat, 4=Meteobridge, 5=WView, 6=WeeWX, 7=WLCOM + imgPathURL: './/images/', // *** Change this to the relative path for your 'Trend' graph /images + oldGauges: 'gauges.htm', // *** Change this to the relative path for your 'old' gauges page. + realtimeInterval: 15, // *** Download data interval, set to your realtime data update interval in seconds + longPoll: false, // if enabled, use long polling and PHP generated data !!only enable if you understand how this is implemented!! + gaugeMobileScaling: 0.85, // scaling factor to apply when displaying the gauges mobile devices, set to 1 to disable (default 0.85) + graphUpdateTime: 15, // period of pop-up data graph refresh, in minutes (default 15) + stationTimeout: 3, // period of no data change before we declare the station off-line, in minutes (default 3) + pageUpdateLimit: 20, // period after which the page stops automatically updating, in minutes (default 20), + // - set to 0 (zero) to disable this feature + pageUpdatePswd: 'its-me', // password to over ride the page updates time-out, do not set to blank even if you do not use a password - http://&pageUpdate=its-me + digitalFont: false, // Font control for the gauges & timer + digitalForecast: false, // Font control for the status display, set this to false for languages that use accented characters in the forecasts + showPopupData: true, // Pop-up data displayed + showPopupGraphs: false, // If pop-up data is displayed, show the graphs? + mobileShowGraphs: false, // If false, on a mobile/narrow display, always disable the graphs + showWindVariation: true, // Show variation in wind direction over the last 10 minutes on the direction gauge + showWindMetar: false, // Show the METAR substring for wind speed/direction over the last 10 minutes on the direction gauge popup + showIndoorTempHum: true, // Show the indoor temperature/humidity options + showCloudGauge: true, // Display the Cloud Base gauge + showUvGauge: true, // Display the UV Index gauge + showSolarGauge: true, // Display the Solar gauge + showSunshineLed: true, // Show 'sun shining now' LED on solar gauge + showRoseGauge: true, // Show the optional Wind Rose gauge + showRoseGaugeOdo: true, // Show the optional Wind Rose gauge wind run Odometer + showRoseOnDirGauge: true, // Show the rose data as sectors on the direction gauge + showGaugeShadow: true, // Show a drop shadow outside the gauges + roundCloudbaseVal: true, // Round the value shown on the cloud base gauge to make it easier to read + // The realtime files should be absolute paths, "/xxx.txt" refers to the public root of your web server realTimeUrlLongPoll: 'realtimegauges-longpoll.php', // *** ALL Users: If using long polling, change to your location of the PHP long poll realtime file *** - // *** the supplied file is for Cumulus only - realTimeUrlCumulus : 'realtimegauges.txt', // *** Cumulus Users: Change to your location of the realtime file *** - realTimeUrlWD : 'customclientraw.txt', // *** WD Users: Change to your location of the ccr file *** - realTimeUrlVWS : 'steelseriesVWSjson.php', // *** VWS Users: Change to your location of the JSON script generator *** - realTimeUrlWC : 'realtimegaugesWC.txt', // *** WeatherCat Users: Change to your location of the JSON script generator *** - realTimeUrlMB : 'MBrealtimegauges.txt', // *** Meteobridge Users: Change to the location of the JSON file - realTimeUrlWView : 'customclientraw.txt', // *** WView Users: Change to your location of the customclientraw.txt file *** - realTimeUrlWeewx : 'gauge-data.txt', // *** WeeWX Users: Change to your location of the gauge data file *** - realTimeUrlWLCOM : 'WLrealtimegauges.php', // *** WLCOM Users: change to location of WLCOMtags.php file *** - useCookies : true, // Persistently store user preferences in a cookie? - tipImages : [], - dashboardMode : false, // Used by Cumulus MX dashboard - SET TO FALSE OTHERWISE - dewDisplayType : 'dew' // Initial 'scale' to display on the 'dew point' gauge. - // 'dew' - Dewpoint - // 'app' - Apparent temperature - // 'wnd' - Wind Chill - // 'feel' - Feels Like - // 'hea' - Heat Index - // 'hum' - Humidex - }, + // *** the supplied file is for Cumulus only + realTimeUrlCumulus: 'realtimegauges.txt', // *** Cumulus Users: Change to your location of the realtime file *** + realTimeUrlWD: 'customclientraw.txt', // *** WD Users: Change to your location of the ccr file *** + realTimeUrlVWS: 'steelseriesVWSjson.php', // *** VWS Users: Change to your location of the JSON script generator *** + realTimeUrlWC: 'realtimegaugesWC.txt', // *** WeatherCat Users: Change to your location of the JSON script generator *** + realTimeUrlMB: 'MBrealtimegauges.txt', // *** Meteobridge Users: Change to the location of the JSON file + realTimeUrlWView: 'customclientraw.txt', // *** WView Users: Change to your location of the customclientraw.txt file *** + realTimeUrlWeewx: 'gauge-data.txt', // *** WeeWX Users: Change to your location of the gauge data file *** + realTimeUrlWLCOM: 'WLrealtimegauges.php', // *** WLCOM Users: change to location of WLCOMtags.php file *** + useCookies: true, // Persistently store user preferences in a cookie? + tip/ images : [], + dashboardMode: false, // Used by Cumulus MX dashboard - SET TO FALSE OTHERWISE + dewDisplayType: 'dew' // Initial 'scale' to display on the 'dew point' gauge. + // 'dew' - Dewpoint + // 'app' - Apparent temperature + // 'wnd' - Wind Chill + // 'feel' - Feels Like + // 'hea' - Heat Index + // 'hum' - Humidex +}, - // Gauge global look'n'feel settings - gaugeGlobals = { - minMaxArea : 'rgba(212,132,134,0.3)', // area sector for today's max/min. (red, green, blue, transparency) - windAvgArea : 'rgba(132,212,134,0.3)', - windVariationSector : 'rgba(120,200,120,0.7)', // only used when rose data is shown on direction gauge - frameDesign : steelseries.FrameDesign.TILTED_GRAY, - background : steelseries.BackgroundColor.BEIGE, - foreground : steelseries.ForegroundType.TYPE1, - pointer : steelseries.PointerType.TYPE8, - pointerColour : steelseries.ColorDef.RED, - dirAvgPointer : steelseries.PointerType.TYPE8, - dirAvgPointerColour : steelseries.ColorDef.BLUE, - gaugeType : steelseries.GaugeType.TYPE4, - lcdColour : steelseries.LcdColor.STANDARD, - knob : steelseries.KnobType.STANDARD_KNOB, - knobStyle : steelseries.KnobStyle.SILVER, - labelFormat : steelseries.LabelNumberFormat.STANDARD, - tickLabelOrientation : steelseries.TickLabelOrientation.HORIZONTAL, // was .NORMAL up to v1.6.4 - rainUseSectionColours : false, // Only one of these colour options should be true - rainUseGradientColours: false, // Set both to false to use the pointer colour - tempTrendVisible : true, - pressureTrendVisible : true, - uvLcdDecimals : 1, - // sunshine threshold values - sunshineThreshold : 50, // the value in W/m² above which we can consider the Sun to be shining, *if* the current value exceeds... - sunshineThresholdPct : 75, // the percentage of theoretical solar irradiance above which we consider the Sun to be shining - // default gauge ranges - before auto-scaling/ranging - tempScaleDefMinC : -20, - tempScaleDefMaxC : 40, - tempScaleDefMinF : 0, - tempScaleDefMaxF : 100, - baroScaleDefMinhPa : 990, - baroScaleDefMaxhPa : 1030, - baroScaleDefMinkPa : 99, - baroScaleDefMaxkPa : 103, - baroScaleDefMininHg : 29.2, - baroScaleDefMaxinHg : 30.4, - windScaleDefMaxMph : 20, - windScaleDefMaxKts : 20, - windScaleDefMaxMs : 10, - windScaleDefMaxKmh : 30, - rainScaleDefMaxmm : 10, - rainScaleDefMaxIn : 0.5, - rainRateScaleDefMaxmm : 10, - rainRateScaleDefMaxIn : 0.5, - uvScaleDefMax : 10, // Northern Europe may be lower - max. value recorded in the UK is 8, so use a scale of 10 for UK - solarGaugeScaleMax : 1000, // Max value to be shown on the solar gauge - theoretical max without atmosphere ~ 1374 W/m² - // - but Davis stations can read up to 1800, use 1000 for Northern Europe? - cloudScaleDefMaxft : 3000, - cloudScaleDefMaxm : 1000, - shadowColour : 'rgba(0,0,0,0.3)' // Colour to use for gauge shadows - default 30% transparent black - }, + // Gauge global look'n'feel settings + gaugeGlobals = { + minMaxArea: 'rgba(212,132,134,0.3)', // area sector for today's max/min. (red, green, blue, transparency) + windAvgArea: 'rgba(132,212,134,0.3)', + windVariationSector: 'rgba(120,200,120,0.7)', // only used when rose data is shown on direction gauge + frameDesign: steelseries.FrameDesign.TILTED_GRAY, + background: steelseries.BackgroundColor.BEIGE, + foreground: steelseries.ForegroundType.TYPE1, + pointer: steelseries.PointerType.TYPE8, + pointerColour: steelseries.ColorDef.RED, + dirAvgPointer: steelseries.PointerType.TYPE8, + dirAvgPointerColour: steelseries.ColorDef.BLUE, + gaugeType: steelseries.GaugeType.TYPE4, + lcdColour: steelseries.LcdColor.STANDARD, + knob: steelseries.KnobType.STANDARD_KNOB, + knobStyle: steelseries.KnobStyle.SILVER, + labelFormat: steelseries.LabelNumberFormat.STANDARD, + tickLabelOrientation: steelseries.TickLabelOrientation.HORIZONTAL, // was .NORMAL up to v1.6.4 + rainUseSectionColours: false, // Only one of these colour options should be true + rainUseGradientColours: false, // Set both to false to use the pointer colour + tempTrendVisible: true, + pressureTrendVisible: true, + uvLcdDecimals: 1, + // sunshine threshold values + sunshineThreshold: 50, // the value in W/m² above which we can consider the Sun to be shining, *if* the current value exceeds... + sunshineThresholdPct: 75, // the percentage of theoretical solar irradiance above which we consider the Sun to be shining + // default gauge ranges - before auto-scaling/ranging + tempScaleDefMinC: -20, + tempScaleDefMaxC: 40, + tempScaleDefMinF: 0, + tempScaleDefMaxF: 100, + baroScaleDefMinhPa: 990, + baroScaleDefMaxhPa: 1030, + baroScaleDefMinkPa: 99, + baroScaleDefMaxkPa: 103, + baroScaleDefMininHg: 29.2, + baroScaleDefMaxinHg: 30.4, + windScaleDefMaxMph: 20, + windScaleDefMaxKts: 20, + windScaleDefMaxMs: 10, + windScaleDefMaxKmh: 30, + rainScaleDefMaxmm: 10, + rainScaleDefMaxIn: 0.5, + rainRateScaleDefMaxmm: 10, + rainRateScaleDefMaxIn: 0.5, + uvScaleDefMax: 10, // Northern Europe may be lower - max. value recorded in the UK is 8, so use a scale of 10 for UK + solarGaugeScaleMax: 1000, // Max value to be shown on the solar gauge - theoretical max without atmosphere ~ 1374 W/m² + // - but Davis stations can read up to 1800, use 1000 for Northern Europe? + cloudScaleDefMaxft: 3000, + cloudScaleDefMaxm: 1000, + shadowColour: 'rgba(0,0,0,0.3)' // Colour to use for gauge shadows - default 30% transparent black + }, - commonParams = { - // Common parameters for all the SteelSeries gauges - fullScaleDeflectionTime: 4, // Bigger numbers (seconds) slow the gauge pointer movements more - gaugeType : gaugeGlobals.gaugeType, - minValue : 0, - niceScale : true, - ledVisible : false, - frameDesign : gaugeGlobals.frameDesign, - backgroundColor : gaugeGlobals.background, - foregroundType : gaugeGlobals.foreground, - pointerType : gaugeGlobals.pointer, - pointerColor : gaugeGlobals.pointerColour, - knobType : gaugeGlobals.knob, - knobStyle : gaugeGlobals.knobStyle, - lcdColor : gaugeGlobals.lcdColour, - lcdDecimals : 1, - digitalFont : config.digitalFont, - tickLabelOrientation : gaugeGlobals.tickLabelOrientation, - labelNumberFormat : gaugeGlobals.labelFormat - }, - firstRun = true, // Used to set-up units & scales etc - userUnitsSet = false, // Tracks if the display units have been set by a user preference - data = {}, // Stores all the values from realtime.txt - tickTockInterval, // The 1s clock interval timer + commonParams = { + // Common parameters for all the SteelSeries gauges + fullScaleDeflectionTime: 4, // Bigger numbers (seconds) slow the gauge pointer movements more + gaugeType: gaugeGlobals.gaugeType, + minValue: 0, + niceScale: true, + ledVisible: false, + frameDesign: gaugeGlobals.frameDesign, + backgroundColor: gaugeGlobals.background, + foregroundType: gaugeGlobals.foreground, + pointerType: gaugeGlobals.pointer, + pointerColor: gaugeGlobals.pointerColour, + knobType: gaugeGlobals.knob, + knobStyle: gaugeGlobals.knobStyle, + lcdColor: gaugeGlobals.lcdColour, + lcdDecimals: 1, + digitalFont: config.digitalFont, + tickLabelOrientation: gaugeGlobals.tickLabelOrientation, + labelNumberFormat: gaugeGlobals.labelFormat + }, + firstRun = true, // Used to set-up units & scales etc + userUnitsSet = false, // Tracks if the display units have been set by a user preference + data = {}, // Stores all the values from realtime.txt + tickTockInterval, // The 1s clock interval timer - // ajaxDelay, used by long polling, the delay between getting a response and queueing the next request, as the default PHP - // script runtime timout is 30 seconds, we do not want the PHP task to run for more than 20 seconds. So queue the next - // request half of the realtime interval, or 20 seconds before it is due, which ever is the larger. - ajaxDelay = config.longPoll ? Math.max(config.realtimeInterval - 20, 0) : config.realtimeInterval, - downloadTimer, // Stores a reference to the ajax download setTimout() timer - timestamp = 0, // the timestamp of last data update on the server. - jqXHR = null, // handle to the jQuery web request - displayUnits = null, // Stores the display units cookie settings - sampleDate, - realtimeVer, // minimum version of the realtime JSON file required - programLink = [ - 'Cumulus', - 'Weather Display', - 'Virtual Weather Station', - 'WeatherCat', - 'Meteobridge', - 'Wview', - 'weewx', - 'Weatherlink.com' - ], + // ajaxDelay, used by long polling, the delay between getting a response and queueing the next request, as the default PHP + // script runtime timout is 30 seconds, we do not want the PHP task to run for more than 20 seconds. So queue the next + // request half of the realtime interval, or 20 seconds before it is due, which ever is the larger. + ajaxDelay = config.longPoll ? Math.max(config.realtimeInterval - 20, 0) : config.realtimeInterval, + downloadTimer, // Stores a reference to the ajax download setTimout() timer + timestamp = 0, // the timestamp of last data update on the server. + jqXHR = null, // handle to the jQuery web request + displayUnits = null, // Stores the display units cookie settings + sampleDate, + realtimeVer, // minimum version of the realtime JSON file required + programLink = [ + 'Cumulus', + 'Weather Display', + 'Virtual Weather Station', + 'WeatherCat', + 'Meteobridge', + 'Wview', + 'weewx', + 'Weatherlink.com' + ], - ledIndicator, statusScroller, statusTimer, + ledIndicator, statusScroller, statusTimer, - gaugeTemp, gaugeDew, gaugeRain, gaugeRRate, - gaugeHum, gaugeBaro, gaugeWind, gaugeDir, - gaugeUV, gaugeSolar, gaugeCloud, gaugeRose, + gaugeTemp, gaugeDew, gaugeRain, gaugeRRate, + gaugeHum, gaugeBaro, gaugeWind, gaugeDir, + gaugeUV, gaugeSolar, gaugeCloud, gaugeRose, - /* _imgBackground, // Uncomment if using a background image on the gauges */ + /* _imgBackground, // Uncomment if using a background image on the gauges */ - // ================================================================================================================== - // Nothing below this line needs to be modified for the gauges as supplied - // - unless you really know what you are doing - // - but remember, if you break it, it's up to you to fix it ;-) - // ================================================================================================================== + // ================================================================================================================== + // Nothing below this line needs to be modified for the gauges as supplied + // - unless you really know what you are doing + // - but remember, if you break it, it's up to you to fix it ;-) + // ================================================================================================================== - // - // init() Called when the document is ready, pre-draws the Status Display then calls - // the first Ajax fetch of realtimegauges.txt. First draw of the gauges now deferred until - // the Ajax data is available as a 'speed up'. - // - init = function (dashboard) { - // Cumulus, Weather Display, VWS, WeatherCat? - switch (config.weatherProgram) { + // + // init() Called when the document is ready, pre-draws the Status Display then calls + // the first Ajax fetch of realtimegauges.txt. First draw of the gauges now deferred until + // the Ajax data is available as a 'speed up'. + // + init = function (dashboard) { + // Cumulus, Weather Display, VWS, WeatherCat? + switch (config.weatherProgram) { case 0: // Cumulus realtimeVer = 12; // minimum version of the realtime JSON file required config.realTimeURL = config.longPoll ? config.realTimeUrlLongPoll : config.realTimeUrlCumulus; - // the trend images to be used for the pop-up data, used in conjunction with config.imgPathURL + // the trend /images to be used for the pop-up data, used in conjunction with config.imgPathURL // by default this is configured for the Cumulus 'standard' web site - // ** If you specify one image in a sub-array, then you MUST provide images for all the other sub-elements + // ** If you specify one image in a sub-array, then you MUST provide /images for all the other sub-elements config.tipImgs = [ // config.tipImgs for Cumulus users using the 'default' weather site ['temp.png', 'intemp.png'], // Temperature: outdoor, indoor // Temperature: dewpoint, apparent, windChill, heatIndex, humidex @@ -253,8 +253,9 @@ gauges = (function () { ]; // WD useer generally use wxgraphs - tweak the CSS to accomadate the different aspect ratio $('.tipimg').css({ - width : '360px', - height: '260px'}); + width: '360px', + height: '260px' + }); break; case 2: // WVS @@ -302,10 +303,10 @@ gauges = (function () { // Meteobridge realtimeVer = 10; // minimum version of the realtime JSON file required config.realTimeURL = config.longPoll ? config.realTimeUrlLongPoll : config.realTimeUrlMB; - config.showPopupGraphs = false; // config.tipImgs - no Meteobridge images available + config.showPopupGraphs = false; // config.tipImgs - no Meteobridge /images available config.showRoseGauge = false; // no windrose data from MB config.showCloudGauge = false; - config.tipImgs = null; // config.tipImgs - no Meteobridge images available + config.tipImgs = null; // config.tipImgs - no Meteobridge /images available config.showWindVariation = false; // no wind variation data from MB break; case 5: @@ -358,10 +359,10 @@ gauges = (function () { // WLCOM realtimeVer = 10; // minimum version of the realtime JSON file required config.realTimeURL = config.realTimeUrlWLCOM; - config.showPopupGraphs = false; // config.tipImgs - no WL images available + config.showPopupGraphs = false; // config.tipImgs - no WL /images available config.showRoseGauge = false; // no windrose data from WL config.showCloudGauge = false; - config.tipImgs = null; // config.tipImgs - no WL images available + config.tipImgs = null; // config.tipImgs - no WL /images available config.showWindVariation = false; // no wind variation data from WL break; default: @@ -370,594 +371,594 @@ gauges = (function () { config.realtimeURL = null; config.showPopupGraphs = false; config.tipImgs = null; // config.tipImgs - unknown - } + } - // Are we running on a phone device (or really low res screen)? - if ($(window).width() < 480) { - // Change the gauge scaling - config.gaugeScaling = config.gaugeMobileScaling; - // Switch off graphs? - config.showPopupGraphs = config.mobileShowGraphs; - } else { - config.gaugeScaling = 1; - } - - // Logo images are used to 'personalise' the gauge backgrounds - // To add a logo to a gauge, add the parameter: - // params.customLayer = _imgBackground; - // to the corresponding drawXxxx() function below. - // - // These are for demo only, to add them remove the comments around the following lines, and - // the _imgBackground definition line above... - /* - _imgBackground = document.createElement('img'); // small logo - $(_imgBackground).attr('src', config.imgPathURL + 'logoSmall.png'); - */ - // End of logo images - - // Get the display units the user last used when they visited before - if present - displayUnits = getCookie('units'); - // Set 'units' radio buttons to match preferred units - if (displayUnits !== null) { - // User wants specific units - userUnitsSet = true; - - // temperature - setRadioCheck('rad_unitsTemp', displayUnits.temp); - data.tempunit = '°' + displayUnits.temp; - // rain - setRadioCheck('rad_unitsRain', displayUnits.rain); - data.rainunit = displayUnits.rain; - // pressure - setRadioCheck('rad_unitsPress', displayUnits.press); - data.pressunit = displayUnits.press; - // wind - setRadioCheck('rad_unitsWind', displayUnits.wind); - data.windunit = displayUnits.wind; - displayUnits.windrun = getWindrunUnits(data.windunit); - // cloud base - setRadioCheck('rad_unitsCloud', displayUnits.cloud); - data.cloudunit = displayUnits.cloud; - } else { - // Set the defaults to metric ) - // DO NOT CHANGE THESE - THE SCRIPT DEPENDS ON THESE DEFAULTS - // The units actually displayed will be read from the realtime.txt file, or from the users last visit cookie - displayUnits = { - temp : 'C', - rain : 'mm', - press : 'hPa', - wind : 'km/h', - windrun: 'km', - cloud : 'm' - }; - - data.tempunit = '°C'; - data.rainunit = 'mm'; - data.pressunit = 'hPa'; - data.windunit = 'km/h'; - data.cloudunit = 'm'; - } - - // enable popup data - if (config.showPopupData) { - ddimgtooltip.showTips = config.showPopupData; - } - - if (config.showPopupGraphs) { - // Note the number of array elements must match 'i' in ddimgtooltip.tiparray() - ddimgtooltip.tiparray[0][0] = (config.tipImgs[0][0] === null ? null : ''); - ddimgtooltip.tiparray[1][0] = (config.tipImgs[1][0] === null ? null : ''); - ddimgtooltip.tiparray[2][0] = (config.tipImgs[2] === null ? null : ''); - ddimgtooltip.tiparray[3][0] = (config.tipImgs[3] === null ? null : ''); - ddimgtooltip.tiparray[4][0] = (config.tipImgs[4][0] === null ? null : ''); - ddimgtooltip.tiparray[5][0] = (config.tipImgs[5] === null ? null : ''); - ddimgtooltip.tiparray[6][0] = (config.tipImgs[6] === null ? null : ''); - ddimgtooltip.tiparray[7][0] = (config.tipImgs[7] === null ? null : ''); - ddimgtooltip.tiparray[8][0] = (config.tipImgs[8] === null ? null : ''); - ddimgtooltip.tiparray[9][0] = (config.tipImgs[9] === null ? null : ''); - ddimgtooltip.tiparray[10][0] = (config.tipImgs[10] === null ? null : ''); - ddimgtooltip.tiparray[11][0] = (config.tipImgs[11] === null ? null : ''); - } - - // draw the status gadgets first, they will display any errors in the initial set-up - ledIndicator = singleLed.getInstance(); - statusScroller = singleStatus.getInstance(); - statusTimer = singleTimer.getInstance(); - - gaugeTemp = singleTemp.getInstance(); - // Export gaugeTemp.update() so it can be called from the HTML code - if (gaugeTemp) {gauges.doTemp = gaugeTemp.update;} - - gaugeDew = singleDew.getInstance(); - // Export gaugeDew.update() so it can be called from the HTML code - if (gaugeDew) {gauges.doDew = gaugeDew.update;} - - gaugeHum = singleHum.getInstance(); - // Export gaugeHum.update() so it can be called from the HTML code - if (gaugeHum) {gauges.doHum = gaugeHum.update;} - - gaugeBaro = singleBaro.getInstance(); - - gaugeWind = singleWind.getInstance(); - gaugeDir = singleDir.getInstance(); - - gaugeRain = singleRain.getInstance(); - gaugeRRate = singleRRate.getInstance(); - - // remove the UV gauge? - if (!config.showUvGauge) { - $('#canvas_uv').parent().remove(); - } else { - gaugeUV = singleUV.getInstance(); - } - - // remove the Solar gauge? - if (!config.showSolarGauge) { - $('#canvas_solar').parent().remove(); - } else { - gaugeSolar = singleSolar.getInstance(); - } - - // remove the Wind Rose? - if (!config.showRoseGauge) { - $('#canvas_rose').parent().remove(); - } else { - gaugeRose = singleRose.getInstance(); - } - - // remove the cloud base gauge? - if (!config.showCloudGauge) { - $('#canvas_cloud').parent().remove(); - // and remove cloudbase unit selection options - $('#cloud').parent().remove(); - } else { - gaugeCloud = singleCloudBase.getInstance(); - } - - // Set the language - changeLang(strings, false); - - if (!dashboard) { - // Go do get the data! - getRealtime(); - - // start a timer to update the status time - tickTockInterval = setInterval( - function () { - $.publish('gauges.clockTick', null); - }, - 1000); - - // start a timer to stop the page updates after the timeout period - if (config.pageUpdateLimit > 0 && getUrlParam('pageUpdate') !== config.pageUpdatePswd) { - setTimeout(pageTimeout, config.pageUpdateLimit * 60 * 1000); - } - } - }, + // Are we running on a phone device (or really low res screen)? + if ($(window).width() < 480) { + // Change the gauge scaling + config.gaugeScaling = config.gaugeMobileScaling; + // Switch off graphs? + config.showPopupGraphs = config.mobileShowGraphs; + } else { + config.gaugeScaling = 1; + } + // Logo /images are used to 'personalise' the gauge backgrounds + // To add a logo to a gauge, add the parameter: + // params.customLayer = _imgBackground; + // to the corresponding drawXxxx() function below. // - // singleXXXX functions define a singleton for each of the gauges - // + // These are for demo only, to add them remove the comments around the following lines, and + // the _imgBackground definition line above... + /* + _imgBackground = document.createElement('img'); // small logo + $(_imgBackground).attr('src', config.imgPathURL + 'logoSmall.png'); + */ + // End of logo /images - // - // Singleton for the LED Indicator - // - singleLed = (function () { - var instance; // Stores a reference to the Singleton - var led; // Stores a reference to the SS LED + // Get the display units the user last used when they visited before - if present + displayUnits = getCookie('units'); + // Set 'units' radio buttons to match preferred units + if (displayUnits !== null) { + // User wants specific units + userUnitsSet = true; - function init() { - // create led indicator - if ($('#canvas_led').length) { - led = new steelseries.Led( - 'canvas_led', { - ledColor: steelseries.LedColor.GREEN_LED, - size : $('#canvas_led').width() - }); + // temperature + setRadioCheck('rad_unitsTemp', displayUnits.temp); + data.tempunit = '°' + displayUnits.temp; + // rain + setRadioCheck('rad_unitsRain', displayUnits.rain); + data.rainunit = displayUnits.rain; + // pressure + setRadioCheck('rad_unitsPress', displayUnits.press); + data.pressunit = displayUnits.press; + // wind + setRadioCheck('rad_unitsWind', displayUnits.wind); + data.windunit = displayUnits.wind; + displayUnits.windrun = getWindrunUnits(data.windunit); + // cloud base + setRadioCheck('rad_unitsCloud', displayUnits.cloud); + data.cloudunit = displayUnits.cloud; + } else { + // Set the defaults to metric ) + // DO NOT CHANGE THESE - THE SCRIPT DEPENDS ON THESE DEFAULTS + // The units actually displayed will be read from the realtime.txt file, or from the users last visit cookie + displayUnits = { + temp: 'C', + rain: 'mm', + press: 'hPa', + wind: 'km/h', + windrun: 'km', + cloud: 'm' + }; - setTitle(strings.led_title); + data.tempunit = '°C'; + data.rainunit = 'mm'; + data.pressunit = 'hPa'; + data.windunit = 'km/h'; + data.cloudunit = 'm'; + } + + // enable popup data + if (config.showPopupData) { + ddimgtooltip.showTips = config.showPopupData; + } + + if (config.showPopupGraphs) { + // Note the number of array elements must match 'i' in ddimgtooltip.tiparray() + ddimgtooltip.tiparray[0][0] = (config.tipImgs[0][0] === null ? null : ''); + ddimgtooltip.tiparray[1][0] = (config.tipImgs[1][0] === null ? null : ''); + ddimgtooltip.tiparray[2][0] = (config.tipImgs[2] === null ? null : ''); + ddimgtooltip.tiparray[3][0] = (config.tipImgs[3] === null ? null : ''); + ddimgtooltip.tiparray[4][0] = (config.tipImgs[4][0] === null ? null : ''); + ddimgtooltip.tiparray[5][0] = (config.tipImgs[5] === null ? null : ''); + ddimgtooltip.tiparray[6][0] = (config.tipImgs[6] === null ? null : ''); + ddimgtooltip.tiparray[7][0] = (config.tipImgs[7] === null ? null : ''); + ddimgtooltip.tiparray[8][0] = (config.tipImgs[8] === null ? null : ''); + ddimgtooltip.tiparray[9][0] = (config.tipImgs[9] === null ? null : ''); + ddimgtooltip.tiparray[10][0] = (config.tipImgs[10] === null ? null : ''); + ddimgtooltip.tiparray[11][0] = (config.tipImgs[11] === null ? null : ''); + } + + // draw the status gadgets first, they will display any errors in the initial set-up + ledIndicator = singleLed.getInstance(); + statusScroller = singleStatus.getInstance(); + statusTimer = singleTimer.getInstance(); + + gaugeTemp = singleTemp.getInstance(); + // Export gaugeTemp.update() so it can be called from the HTML code + if (gaugeTemp) { gauges.doTemp = gaugeTemp.update; } + + gaugeDew = singleDew.getInstance(); + // Export gaugeDew.update() so it can be called from the HTML code + if (gaugeDew) { gauges.doDew = gaugeDew.update; } + + gaugeHum = singleHum.getInstance(); + // Export gaugeHum.update() so it can be called from the HTML code + if (gaugeHum) { gauges.doHum = gaugeHum.update; } + + gaugeBaro = singleBaro.getInstance(); + + gaugeWind = singleWind.getInstance(); + gaugeDir = singleDir.getInstance(); + + gaugeRain = singleRain.getInstance(); + gaugeRRate = singleRRate.getInstance(); + + // remove the UV gauge? + if (!config.showUvGauge) { + $('#canvas_uv').parent().remove(); + } else { + gaugeUV = singleUV.getInstance(); + } + + // remove the Solar gauge? + if (!config.showSolarGauge) { + $('#canvas_solar').parent().remove(); + } else { + gaugeSolar = singleSolar.getInstance(); + } + + // remove the Wind Rose? + if (!config.showRoseGauge) { + $('#canvas_rose').parent().remove(); + } else { + gaugeRose = singleRose.getInstance(); + } + + // remove the cloud base gauge? + if (!config.showCloudGauge) { + $('#canvas_cloud').parent().remove(); + // and remove cloudbase unit selection options + $('#cloud').parent().remove(); + } else { + gaugeCloud = singleCloudBase.getInstance(); + } + + // Set the language + changeLang(strings, false); + + if (!dashboard) { + // Go do get the data! + getRealtime(); + + // start a timer to update the status time + tickTockInterval = setInterval( + function () { + $.publish('gauges.clockTick', null); + }, + 1000); + + // start a timer to stop the page updates after the timeout period + if (config.pageUpdateLimit > 0 && getUrlParam('pageUpdate') !== config.pageUpdatePswd) { + setTimeout(pageTimeout, config.pageUpdateLimit * 60 * 1000); + } + } + }, + + // + // singleXXXX functions define a singleton for each of the gauges + // + + // + // Singleton for the LED Indicator + // + singleLed = (function () { + var instance; // Stores a reference to the Singleton + var led; // Stores a reference to the SS LED + + function init() { + // create led indicator + if ($('#canvas_led').length) { + led = new steelseries.Led( + 'canvas_led', { + ledColor: steelseries.LedColor.GREEN_LED, + size: $('#canvas_led').width() + }); + + setTitle(strings.led_title); + } + + function setTitle(newTitle) { + $('#canvas_led').attr('title', newTitle); + } + + function setLedColor(newColour) { + if (led) { + led.setLedColor(newColour); } + } - function setTitle(newTitle) { - $('#canvas_led').attr('title', newTitle); + function setLedOnOff(onState) { + if (led) { + led.setLedOnOff(onState); } + } - function setLedColor(newColour) { - if (led) { - led.setLedColor(newColour); - } + function blink(blinkState) { + if (led) { + led.blink(blinkState); } - - function setLedOnOff(onState) { - if (led) { - led.setLedOnOff(onState); - } - } - - function blink(blinkState) { - if (led) { - led.blink(blinkState); - } - } - - return { - setTitle : setTitle, - setLedColor: setLedColor, - setLedOnOff: setLedOnOff, - blink : blink - }; } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + setTitle: setTitle, + setLedColor: setLedColor, + setLedOnOff: setLedOnOff, + blink: blink }; - })(), + } - // - // Singleton for the Status Scroller - // - singleStatus = (function () { - var instance; // Stores a reference to the Singleton - var scroller; // Stores a reference to the SS scrolling display - - function init() { - // create forecast display - if ($('#canvas_status').length) { - scroller = new steelseries.DisplaySingle( - 'canvas_status', { - width : $('#canvas_status').width(), - height : $('#canvas_status').height(), - lcdColor : gaugeGlobals.lcdColour, - unitStringVisible: false, - value : strings.statusStr, - digitalFont : config.digitalForecast, - valuesNumeric : false, - autoScroll : true, - alwaysScroll : false - }); + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); } + return instance; + } + }; + })(), - function setValue(newTxt) { - if (scroller) { - scroller.setValue(newTxt); - } + // + // Singleton for the Status Scroller + // + singleStatus = (function () { + var instance; // Stores a reference to the Singleton + var scroller; // Stores a reference to the SS scrolling display + + function init() { + // create forecast display + if ($('#canvas_status').length) { + scroller = new steelseries.DisplaySingle( + 'canvas_status', { + width: $('#canvas_status').width(), + height: $('#canvas_status').height(), + lcdColor: gaugeGlobals.lcdColour, + unitStringVisible: false, + value: strings.statusStr, + digitalFont: config.digitalForecast, + valuesNumeric: false, + autoScroll: true, + alwaysScroll: false + }); + } + + function setValue(newTxt) { + if (scroller) { + scroller.setValue(newTxt); } + } - return {setText: setValue}; + return { setText: setValue }; + } + + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), + + // + // Singleton for the Status Timer + // + singleTimer = (function () { + var instance, // Stores a reference to the Singleton + lcd, // Stores a reference to the SS LED + count = 1; + + function init() { + function tick() { + if (lcd) { + lcd.setValue(count); + count += config.longPoll ? 1 : -1; + } + } + + function reset(val) { + count = val; + } + + function setValue(newVal) { + if (lcd) { + lcd.setValue(newVal); + } + } + + // create timer display + if ($('#canvas_timer').length) { + lcd = new steelseries.DisplaySingle( + 'canvas_timer', { + width: $('#canvas_timer').width(), + height: $('#canvas_timer').height(), + lcdColor: gaugeGlobals.lcdColour, + lcdDecimals: 0, + unitString: strings.timer, + unitStringVisible: true, + digitalFont: config.digitalFont, + value: count + }); + // subscribe to data updates + $.subscribe('gauges.clockTick', tick); } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + reset: reset, + setValue: setValue }; - })(), + } - // - // Singleton for the Status Timer - // - singleTimer = (function () { - var instance, // Stores a reference to the Singleton - lcd, // Stores a reference to the SS LED - count = 1; + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), - function init() { - function tick() { - if (lcd) { - lcd.setValue(count); - count += config.longPoll ? 1 : -1; - } + // + // Singleton for the Temperature Gauge + // + singleTemp = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters + + function init() { + var params = $.extend(true, {}, commonParams); + + // define temperature gauge start values + cache.sections = createTempSections(true); + cache.areas = []; + cache.minValue = gaugeGlobals.tempScaleDefMinC; + cache.maxValue = gaugeGlobals.tempScaleDefMaxC; + cache.title = strings.temp_title_out; + cache.value = gaugeGlobals.tempScaleDefMinC + 0.0001; + cache.maxMinVisible = false; + cache.selected = 'out'; + + // create temperature radial gauge + if ($('#canvas_temp').length) { + params.size = Math.ceil($('#canvas_temp').width() * config.gaugeScaling); + params.section = cache.sections; + params.area = cache.areas; + params.minValue = cache.minValue; + params.maxValue = cache.maxValue; + params.thresholdVisible = false; + params.minMeasuredValueVisible = cache.maxMinVisible; + params.maxMeasuredValueVisible = cache.maxMinVisible; + params.titleString = cache.title; + params.unitString = data.tempunit; + params.trendVisible = gaugeGlobals.tempTrendVisible; + // params.customLayer = _imgBackground; // uncomment to add a background image - See Logo /images above + + ssGauge = new steelseries.Radial('canvas_temp', params); + ssGauge.setValue(cache.value); + + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_temp').css({ width: params.size + 'px', height: params.size + 'px' }); } - function reset(val) { - count = val; + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_temp').css(gaugeShadow(params.size)); } - function setValue(newVal) { - if (lcd) { - lcd.setValue(newVal); - } + // remove indoor temperature/humidity options? + if (!config.showIndoorTempHum) { + $('#rad_temp1').remove(); + $('#lab_temp1').remove(); + $('#rad_temp2').remove(); + $('#lab_temp2').remove(); + $('#rad_hum1').remove(); + $('#lab_hum1').remove(); + $('#rad_hum2').remove(); + $('#lab_hum2').remove(); } - // create timer display - if ($('#canvas_timer').length) { - lcd = new steelseries.DisplaySingle( - 'canvas_timer', { - width : $('#canvas_timer').width(), - height : $('#canvas_timer').height(), - lcdColor : gaugeGlobals.lcdColour, - lcdDecimals : 0, - unitString : strings.timer, - unitStringVisible: true, - digitalFont : config.digitalFont, - value : count - }); - // subscribe to data updates - $.subscribe('gauges.clockTick', tick); - } - - return { - reset : reset, - setValue: setValue - }; + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; } - return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; + function update() { + var sel = cache.selected; + + // Argument length === 1 when called from radio input + // Argument length === 2 when called from event handler + if (arguments.length === 1) { + sel = arguments[0].value; } - }; - })(), - // - // Singleton for the Temperature Gauge - // - singleTemp = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + // if rad isn't specified, just use existing value + var t1, scaleStep, tip; - function init() { - var params = $.extend(true, {}, commonParams); + cache.minValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMinC : gaugeGlobals.tempScaleDefMinF; + cache.maxValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMaxC : gaugeGlobals.tempScaleDefMaxF; - // define temperature gauge start values - cache.sections = createTempSections(true); - cache.areas = []; - cache.minValue = gaugeGlobals.tempScaleDefMinC; - cache.maxValue = gaugeGlobals.tempScaleDefMaxC; - cache.title = strings.temp_title_out; - cache.value = gaugeGlobals.tempScaleDefMinC + 0.0001; - cache.maxMinVisible = false; - cache.selected = 'out'; - - // create temperature radial gauge - if ($('#canvas_temp').length) { - params.size = Math.ceil($('#canvas_temp').width() * config.gaugeScaling); - params.section = cache.sections; - params.area = cache.areas; - params.minValue = cache.minValue; - params.maxValue = cache.maxValue; - params.thresholdVisible = false; - params.minMeasuredValueVisible = cache.maxMinVisible; - params.maxMeasuredValueVisible = cache.maxMinVisible; - params.titleString = cache.title; - params.unitString = data.tempunit; - params.trendVisible = gaugeGlobals.tempTrendVisible; - // params.customLayer = _imgBackground; // uncomment to add a background image - See Logo Images above - - ssGauge = new steelseries.Radial('canvas_temp', params); - ssGauge.setValue(cache.value); - - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_temp').css({width: params.size + 'px', height: params.size + 'px'}); + if (sel === 'out') { + cache.low = extractDecimal(data.tempTL); + cache.high = extractDecimal(data.tempTH); + cache.lowScale = getMinTemp(cache.minValue); + cache.highScale = getMaxTemp(cache.maxValue); + cache.value = extractDecimal(data.temp); + cache.title = strings.temp_title_out; + cache.loc = strings.temp_out_info; + cache.trendVal = extractDecimal(data.temptrend); + cache.popupImg = 0; + if (gaugeGlobals.tempTrendVisible) { + t1 = tempTrend(+cache.trendVal, data.tempunit, false); + if (t1 === -9999) { + // trend value isn't currently available + cache.trend = steelseries.TrendState.OFF; + } else if (t1 > 0) { + cache.trend = steelseries.TrendState.UP; + } else if (t1 < 0) { + cache.trend = steelseries.TrendState.DOWN; + } else { + cache.trend = steelseries.TrendState.STEADY; + } } - - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_temp').css(gaugeShadow(params.size)); - } - - // remove indoor temperature/humidity options? - if (!config.showIndoorTempHum) { - $('#rad_temp1').remove(); - $('#lab_temp1').remove(); - $('#rad_temp2').remove(); - $('#lab_temp2').remove(); - $('#rad_hum1').remove(); - $('#lab_hum1').remove(); - $('#rad_hum2').remove(); - $('#lab_hum2').remove(); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); } else { - // cannot draw gauge, return null - return null; - } - - function update() { - var sel = cache.selected; - - // Argument length === 1 when called from radio input - // Argument length === 2 when called from event handler - if (arguments.length === 1) { - sel = arguments[0].value; - } - - // if rad isn't specified, just use existing value - var t1, scaleStep, tip; - - cache.minValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMinC : gaugeGlobals.tempScaleDefMinF; - cache.maxValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMaxC : gaugeGlobals.tempScaleDefMaxF; - - if (sel === 'out') { - cache.low = extractDecimal(data.tempTL); - cache.high = extractDecimal(data.tempTH); + // Indoor + cache.title = strings.temp_title_in; + cache.loc = strings.temp_in_info; + cache.value = extractDecimal(data.intemp); + cache.popupImg = 1; + if (data.intempTL && data.intempTH) { + // Indoor - and Max/Min values supplied + cache.low = extractDecimal(data.intempTL); + cache.high = extractDecimal(data.intempTH); cache.lowScale = getMinTemp(cache.minValue); cache.highScale = getMaxTemp(cache.maxValue); - cache.value = extractDecimal(data.temp); - cache.title = strings.temp_title_out; - cache.loc = strings.temp_out_info; - cache.trendVal = extractDecimal(data.temptrend); - cache.popupImg = 0; - if (gaugeGlobals.tempTrendVisible) { - t1 = tempTrend(+cache.trendVal, data.tempunit, false); - if (t1 === -9999) { - // trend value isn't currently available - cache.trend = steelseries.TrendState.OFF; - } else if (t1 > 0) { - cache.trend = steelseries.TrendState.UP; - } else if (t1 < 0) { - cache.trend = steelseries.TrendState.DOWN; - } else { - cache.trend = steelseries.TrendState.STEADY; - } - } } else { - // Indoor - cache.title = strings.temp_title_in; - cache.loc = strings.temp_in_info; - cache.value = extractDecimal(data.intemp); - cache.popupImg = 1; - if (data.intempTL && data.intempTH) { - // Indoor - and Max/Min values supplied - cache.low = extractDecimal(data.intempTL); - cache.high = extractDecimal(data.intempTH); - cache.lowScale = getMinTemp(cache.minValue); - cache.highScale = getMaxTemp(cache.maxValue); - } else { - // Indoor - no Max/Min values supplied - cache.low = cache.value; - cache.lowScale = cache.value; - cache.high = cache.value; - cache.highScale = cache.value; - } - if (gaugeGlobals.tempTrendVisible) { - cache.trend = steelseries.TrendState.OFF; - } + // Indoor - no Max/Min values supplied + cache.low = cache.value; + cache.lowScale = cache.value; + cache.high = cache.value; + cache.highScale = cache.value; } - - // has the gauge type changed? - if (cache.selected !== sel) { - cache.selected = sel; - // Change gauge title - ssGauge.setTitleString(cache.title); - ssGauge.setMaxMeasuredValueVisible(cache.maxMinVisible); - ssGauge.setMinMeasuredValueVisible(cache.maxMinVisible); - if (config.showPopupGraphs && config.tipImgs[0][cache.popupImg] !== null) { - var cacheDefeat = '?' + $('#imgtip0_img').attr('src').split('?')[1]; - $('#imgtip0_img').attr('src', config.imgPathURL + config.tipImgs[0][cache.popupImg] + cacheDefeat); - } - } - - // auto scale the ranges - scaleStep = data.tempunit[1] === 'C' ? 10 : 20; - while (cache.lowScale < cache.minValue) { - cache.minValue -= scaleStep; - if (cache.highScale <= cache.maxValue - scaleStep) { - cache.maxValue -= scaleStep; - } - } - while (cache.highScale > cache.maxValue) { - cache.maxValue += scaleStep; - if (cache.minValue >= cache.minValue + scaleStep) { - cache.minValue += scaleStep; - } - } - - if (cache.minValue !== ssGauge.getMinValue() || cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setMinValue(cache.minValue); - ssGauge.setMaxValue(cache.maxValue); - ssGauge.setValue(cache.minValue); - } - if (cache.selected === 'out') { - cache.areas = [steelseries.Section(+cache.low, +cache.high, gaugeGlobals.minMaxArea)]; - } else if (data.intempTL && data.intempTH) { - // Indoor and min/max avaiable - cache.areas = [steelseries.Section(+cache.low, +cache.high, gaugeGlobals.minMaxArea)]; - } else { - // Indoor no min/max avaiable - cache.areas = []; - } - if (gaugeGlobals.tempTrendVisible) { - ssGauge.setTrend(cache.trend); + cache.trend = steelseries.TrendState.OFF; } - ssGauge.setArea(cache.areas); - ssGauge.setValueAnimated(+cache.value); + } - if (ddimgtooltip.showTips) { - // update tooltip - if (cache.selected === 'out') { - tip = cache.loc + ' - ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TtempTL + - ' | ' + - strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TtempTH; - if (cache.trendVal !== -9999) { - tip += '
' + - strings.temp_trend_info + ': ' + tempTrend(cache.trendVal, data.tempunit, true) + - ' ' + cache.trendVal + data.tempunit + '/h'; - } - } else if (data.TintempTL && data.TintempTH) { - // Indoor and min/max available - tip = cache.loc + ' - ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TintempTL + - ' | ' + - strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TintempTH; - } else { - // Indoor no min/max - tip = cache.loc + ': ' + data.intemp + data.tempunit; - } - $('#imgtip0_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[0][cache.popupImg] !== null) { + // has the gauge type changed? + if (cache.selected !== sel) { + cache.selected = sel; + // Change gauge title + ssGauge.setTitleString(cache.title); + ssGauge.setMaxMeasuredValueVisible(cache.maxMinVisible); + ssGauge.setMinMeasuredValueVisible(cache.maxMinVisible); + if (config.showPopupGraphs && config.tipImgs[0][cache.popupImg] !== null) { + var cacheDefeat = '?' + $('#imgtip0_img').attr('src').split('?')[1]; $('#imgtip0_img').attr('src', config.imgPathURL + config.tipImgs[0][cache.popupImg] + cacheDefeat); } } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + // auto scale the ranges + scaleStep = data.tempunit[1] === 'C' ? 10 : 20; + while (cache.lowScale < cache.minValue) { + cache.minValue -= scaleStep; + if (cache.highScale <= cache.maxValue - scaleStep) { + cache.maxValue -= scaleStep; + } + } + while (cache.highScale > cache.maxValue) { + cache.maxValue += scaleStep; + if (cache.minValue >= cache.minValue + scaleStep) { + cache.minValue += scaleStep; + } + } + + if (cache.minValue !== ssGauge.getMinValue() || cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setMinValue(cache.minValue); + ssGauge.setMaxValue(cache.maxValue); + ssGauge.setValue(cache.minValue); + } + if (cache.selected === 'out') { + cache.areas = [steelseries.Section(+cache.low, +cache.high, gaugeGlobals.minMaxArea)]; + } else if (data.intempTL && data.intempTH) { + // Indoor and min/max avaiable + cache.areas = [steelseries.Section(+cache.low, +cache.high, gaugeGlobals.minMaxArea)]; + } else { + // Indoor no min/max avaiable + cache.areas = []; + } + + if (gaugeGlobals.tempTrendVisible) { + ssGauge.setTrend(cache.trend); + } + ssGauge.setArea(cache.areas); + ssGauge.setValueAnimated(+cache.value); + + if (ddimgtooltip.showTips) { + // update tooltip + if (cache.selected === 'out') { + tip = cache.loc + ' - ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TtempTL + + ' | ' + + strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TtempTH; + if (cache.trendVal !== -9999) { + tip += '
' + + strings.temp_trend_info + ': ' + tempTrend(cache.trendVal, data.tempunit, true) + + ' ' + cache.trendVal + data.tempunit + '/h'; + } + } else if (data.TintempTL && data.TintempTH) { + // Indoor and min/max available + tip = cache.loc + ' - ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TintempTL + + ' | ' + + strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TintempTH; + } else { + // Indoor no min/max + tip = cache.loc + ': ' + data.intemp + data.tempunit; + } + $('#imgtip0_txt').html(tip); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[0][cache.popupImg] !== null) { + $('#imgtip0_img').attr('src', config.imgPathURL + config.tipImgs[0][cache.popupImg] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), // End singleTemp() + } // End of init() - // - // Singleton for the Dewpoint Gauge - // - singleDew = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), // End singleTemp() - function init() { - var params = $.extend(true, {}, commonParams); - var tmp; + // + // Singleton for the Dewpoint Gauge + // + singleDew = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // define dew point gauge start values - cache.sections = createTempSections(true); - cache.areas = []; - cache.minValue = gaugeGlobals.tempScaleDefMinC; - cache.maxValue = gaugeGlobals.tempScaleDefMaxC; - cache.value = gaugeGlobals.tempScaleDefMinC + 0.0001; - // Has the end user selected a preferred 'scale' before - tmp = getCookie('dewGauge'); - cache.selected = tmp !== null ? tmp : config.dewDisplayType; - setRadioCheck('rad_dew', cache.selected); - switch (cache.selected) { + function init() { + var params = $.extend(true, {}, commonParams); + var tmp; + + // define dew point gauge start values + cache.sections = createTempSections(true); + cache.areas = []; + cache.minValue = gaugeGlobals.tempScaleDefMinC; + cache.maxValue = gaugeGlobals.tempScaleDefMaxC; + cache.value = gaugeGlobals.tempScaleDefMinC + 0.0001; + // Has the end user selected a preferred 'scale' before + tmp = getCookie('dewGauge'); + cache.selected = tmp !== null ? tmp : config.dewDisplayType; + setRadioCheck('rad_dew', cache.selected); + switch (cache.selected) { case 'dew': cache.title = strings.dew_title; cache.popupImg = 0; @@ -982,62 +983,62 @@ gauges = (function () { cache.title = strings.humdx_title; cache.popupImg = 4; // no default - } - cache.minMeasuredVisible = false; - cache.maxMeasuredVisible = false; + } + cache.minMeasuredVisible = false; + cache.maxMeasuredVisible = false; - // create dew point radial gauge - if ($('#canvas_dew').length) { - params.size = Math.ceil($('#canvas_dew').width() * config.gaugeScaling); - params.section = cache.sections; - params.area = cache.areas; - params.minValue = cache.minValue; - params.maxValue = cache.maxValue; - params.thresholdVisible = false; - params.titleString = cache.title; - params.unitString = data.tempunit; + // create dew point radial gauge + if ($('#canvas_dew').length) { + params.size = Math.ceil($('#canvas_dew').width() * config.gaugeScaling); + params.section = cache.sections; + params.area = cache.areas; + params.minValue = cache.minValue; + params.maxValue = cache.maxValue; + params.thresholdVisible = false; + params.titleString = cache.title; + params.unitString = data.tempunit; - ssGauge = new steelseries.Radial('canvas_dew', params); - ssGauge.setValue(cache.value); + ssGauge = new steelseries.Radial('canvas_dew', params); + ssGauge.setValue(cache.value); - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_dew').css({width: params.size + 'px', height: params.size + 'px'}); - } - - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_dew').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_dew').css({ width: params.size + 'px', height: params.size + 'px' }); } - function update() { - // if rad isn't specified, just use existing value - var sel = cache.selected; + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_dew').css(gaugeShadow(params.size)); + } - // Argument length === 2 when called from event handler - if (arguments.length === 1) { - sel = arguments[0].value; - // save the choice in a cookie - setCookie('dewGauge', sel); - } + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } - var tip, scaleStep; + function update() { + // if rad isn't specified, just use existing value + var sel = cache.selected; - cache.minValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMinC : gaugeGlobals.tempScaleDefMinF; - cache.maxValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMaxC : gaugeGlobals.tempScaleDefMaxF; + // Argument length === 2 when called from event handler + if (arguments.length === 1) { + sel = arguments[0].value; + // save the choice in a cookie + setCookie('dewGauge', sel); + } - cache.lowScale = getMinTemp(cache.minValue); - cache.highScale = getMaxTemp(cache.maxValue); + var tip, scaleStep; - switch (sel) { + cache.minValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMinC : gaugeGlobals.tempScaleDefMinF; + cache.maxValue = data.tempunit[1] === 'C' ? gaugeGlobals.tempScaleDefMaxC : gaugeGlobals.tempScaleDefMaxF; + + cache.lowScale = getMinTemp(cache.minValue); + cache.highScale = getMaxTemp(cache.maxValue); + + switch (sel) { case 'dew': // dew point cache.low = extractDecimal(data.dewpointTL); cache.high = extractDecimal(data.dewpointTH); @@ -1048,9 +1049,9 @@ gauges = (function () { cache.maxMeasuredVisible = false; cache.popupImg = 0; tip = strings.dew_info + ':' + - '
' + - '- ' + strings.lowest_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TdewpointTL + - ' | ' + strings.highest_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TdewpointTH; + '
' + + '- ' + strings.lowest_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TdewpointTL + + ' | ' + strings.highest_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TdewpointTH; break; case 'app': // apparent temperature cache.low = extractDecimal(data.apptempTL); @@ -1062,9 +1063,9 @@ gauges = (function () { cache.maxMeasuredVisible = false; cache.popupImg = 1; tip = tip = strings.apptemp_info + ':' + - '
' + - '- ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TapptempTL + - ' | ' + strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TapptempTH; + '
' + + '- ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TapptempTL + + ' | ' + strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TapptempTH; break; case 'feel': // feels like cache.low = extractDecimal(data.feelslikeTL); @@ -1076,9 +1077,9 @@ gauges = (function () { cache.maxMeasuredVisible = false; cache.popupImg = 1; tip = tip = strings.feel_info + ':' + - '
' + - '- ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TfeelslikeTL + - ' | ' + strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TfeelslikeTH; + '
' + + '- ' + strings.lowestF_info + ': ' + cache.low + data.tempunit + ' ' + strings.at + ' ' + data.TfeelslikeTL + + ' | ' + strings.highestF_info + ': ' + cache.high + data.tempunit + ' ' + strings.at + ' ' + data.TfeelslikeTH; break; case 'wnd': // wind chill cache.low = extractDecimal(data.wchillTL); @@ -1118,683 +1119,683 @@ gauges = (function () { tip = strings.humdx_info + ': ' + cache.value + data.tempunit; break; // no default - } - - if (cache.selected !== sel) { - cache.selected = sel; - // change gauge title - ssGauge.setTitleString(cache.title); - // and graph image - if (config.showPopupGraphs && config.tipImgs[1][cache.popupImg] !== null) { - var cacheDefeat = '?' + $('#imgtip1_img').attr('src').split('?')[1]; - $('#imgtip1_img').attr('src', config.imgPathURL + config.tipImgs[1][cache.popupImg] + cacheDefeat); - } - } - - // auto scale the ranges - scaleStep = data.tempunit[1] === 'C' ? 10 : 20; - while (cache.lowScale < cache.minValue) { - cache.minValue -= scaleStep; - if (cache.highScale <= cache.maxValue - scaleStep) { - cache.maxValue -= scaleStep; - } - } - while (cache.highScale > cache.maxValue) { - cache.maxValue += scaleStep; - if (cache.minValue >= cache.minValue + scaleStep) { - cache.minValue += scaleStep; - } - } - - if (cache.minValue !== ssGauge.getMinValue() || cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setMinValue(cache.minValue); - ssGauge.setMaxValue(cache.maxValue); - ssGauge.setValue(cache.minValue); - } - ssGauge.setMinMeasuredValueVisible(cache.minMeasuredVisible); - ssGauge.setMaxMeasuredValueVisible(cache.maxMeasuredVisible); - ssGauge.setMinMeasuredValue(+cache.low); - ssGauge.setMaxMeasuredValue(+cache.high); - ssGauge.setArea(cache.areas); - ssGauge.setValueAnimated(+cache.value); - - if (ddimgtooltip.showTips) { - // update tooltip - $('#imgtip1_txt').html(tip); - } } - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[1][cache.popupImg] !== null) { + if (cache.selected !== sel) { + cache.selected = sel; + // change gauge title + ssGauge.setTitleString(cache.title); + // and graph image + if (config.showPopupGraphs && config.tipImgs[1][cache.popupImg] !== null) { + var cacheDefeat = '?' + $('#imgtip1_img').attr('src').split('?')[1]; $('#imgtip1_img').attr('src', config.imgPathURL + config.tipImgs[1][cache.popupImg] + cacheDefeat); } } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + // auto scale the ranges + scaleStep = data.tempunit[1] === 'C' ? 10 : 20; + while (cache.lowScale < cache.minValue) { + cache.minValue -= scaleStep; + if (cache.highScale <= cache.maxValue - scaleStep) { + cache.maxValue -= scaleStep; + } + } + while (cache.highScale > cache.maxValue) { + cache.maxValue += scaleStep; + if (cache.minValue >= cache.minValue + scaleStep) { + cache.minValue += scaleStep; + } + } + + if (cache.minValue !== ssGauge.getMinValue() || cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setMinValue(cache.minValue); + ssGauge.setMaxValue(cache.maxValue); + ssGauge.setValue(cache.minValue); + } + ssGauge.setMinMeasuredValueVisible(cache.minMeasuredVisible); + ssGauge.setMaxMeasuredValueVisible(cache.maxMeasuredVisible); + ssGauge.setMinMeasuredValue(+cache.low); + ssGauge.setMaxMeasuredValue(+cache.high); + ssGauge.setArea(cache.areas); + ssGauge.setValueAnimated(+cache.value); + + if (ddimgtooltip.showTips) { + // update tooltip + $('#imgtip1_txt').html(tip); + } + } + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[1][cache.popupImg] !== null) { + $('#imgtip1_img').attr('src', config.imgPathURL + config.tipImgs[1][cache.popupImg] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), // End of singleDew() + } // End of init() - // - // Singleton for the Rainfall Gauge - // - singleRain = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), // End of singleDew() - function init() { - var params = $.extend(true, {}, commonParams); + // + // Singleton for the Rainfall Gauge + // + singleRain = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // define rain gauge start values - cache.maxValue = gaugeGlobals.rainScaleDefMaxmm; - cache.value = 0.0001; - cache.title = strings.rain_title; - cache.lcdDecimals = 1; - cache.scaleDecimals = 1; - cache.labelNumberFormat = gaugeGlobals.labelFormat; - cache.sections = (gaugeGlobals.rainUseSectionColours ? createRainfallSections(true) : []); - cache.valGrad = (gaugeGlobals.rainUseGradientColours ? createRainfallGradient(true) : null); + function init() { + var params = $.extend(true, {}, commonParams); - // create rain radial bargraph gauge - if ($('#canvas_rain').length) { - params.size = Math.ceil($('#canvas_rain').width() * config.gaugeScaling); - params.maxValue = cache.maxValue; - params.thresholdVisible = false; - params.titleString = cache.title; - params.unitString = data.rainunit; - params.valueColor = steelseries.ColorDef.BLUE; - params.valueGradient = cache.valGrad; - params.useValueGradient = gaugeGlobals.rainUseGradientColours; - params.useSectionColors = gaugeGlobals.rainUseSectionColour; - params.useSectionColors = gaugeGlobals.rainUseSectionColours; - params.labelNumberFormat = cache.labelNumberFormat; - params.fractionalScaleDecimals = cache.scaleDecimals; - params.niceScale = false; + // define rain gauge start values + cache.maxValue = gaugeGlobals.rainScaleDefMaxmm; + cache.value = 0.0001; + cache.title = strings.rain_title; + cache.lcdDecimals = 1; + cache.scaleDecimals = 1; + cache.labelNumberFormat = gaugeGlobals.labelFormat; + cache.sections = (gaugeGlobals.rainUseSectionColours ? createRainfallSections(true) : []); + cache.valGrad = (gaugeGlobals.rainUseGradientColours ? createRainfallGradient(true) : null); - ssGauge = new steelseries.RadialBargraph('canvas_rain', params); - ssGauge.setValue(cache.value); + // create rain radial bargraph gauge + if ($('#canvas_rain').length) { + params.size = Math.ceil($('#canvas_rain').width() * config.gaugeScaling); + params.maxValue = cache.maxValue; + params.thresholdVisible = false; + params.titleString = cache.title; + params.unitString = data.rainunit; + params.valueColor = steelseries.ColorDef.BLUE; + params.valueGradient = cache.valGrad; + params.useValueGradient = gaugeGlobals.rainUseGradientColours; + params.useSectionColors = gaugeGlobals.rainUseSectionColour; + params.useSectionColors = gaugeGlobals.rainUseSectionColours; + params.labelNumberFormat = cache.labelNumberFormat; + params.fractionalScaleDecimals = cache.scaleDecimals; + params.niceScale = false; - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_rain').css({width: params.size + 'px', height: params.size + 'px'}); - } + ssGauge = new steelseries.RadialBargraph('canvas_rain', params); + ssGauge.setValue(cache.value); - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_rain').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_rain').css({ width: params.size + 'px', height: params.size + 'px' }); } - function update() { - cache.value = extractDecimal(data.rfall); - if (data.rainunit === 'mm') { // 10, 20, 30... - cache.maxValue = Math.max(nextHighest(cache.value, 10), gaugeGlobals.rainScaleDefMaxmm); + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_rain').css(gaugeShadow(params.size)); + } + + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } + + function update() { + cache.value = extractDecimal(data.rfall); + if (data.rainunit === 'mm') { // 10, 20, 30... + cache.maxValue = Math.max(nextHighest(cache.value, 10), gaugeGlobals.rainScaleDefMaxmm); + } else { + // inches 0.5, 1.0, 2.0, 3.0 ... 10.0, 12.0, 14.0 + if (cache.value <= 1) { + cache.maxValue = Math.max(nextHighest(cache.value, 0.5), gaugeGlobals.rainScaleDefMaxIn); + } else if (cache.value <= 6) { + cache.maxValue = Math.max(nextHighest(cache.value, 1), gaugeGlobals.rainScaleDefMaxIn); } else { - // inches 0.5, 1.0, 2.0, 3.0 ... 10.0, 12.0, 14.0 - if (cache.value <= 1) { - cache.maxValue = Math.max(nextHighest(cache.value, 0.5), gaugeGlobals.rainScaleDefMaxIn); - } else if (cache.value <= 6) { - cache.maxValue = Math.max(nextHighest(cache.value, 1), gaugeGlobals.rainScaleDefMaxIn); - } else { - cache.maxValue = Math.max(nextHighest(cache.value, 2), gaugeGlobals.rainScaleDefMaxIn); - } - cache.scaleDecimals = cache.maxValue < 1 ? 2 : 1; - } - - if (cache.maxValue !== ssGauge.getMaxValue()) { - // Gauge scale is too low, increase it. - // First set the pointer back to zero so we get a nice animation - ssGauge.setValue(0); - // and redraw the gauge with the new scale - ssGauge.setFractionalScaleDecimals(cache.scaleDecimals); - ssGauge.setMaxValue(cache.maxValue); - } - ssGauge.setValueAnimated(cache.value); - - if (ddimgtooltip.showTips) { - // update tooltip - $('#imgtip2_txt').html(strings.LastRain_info + ': ' + data.LastRained); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[2] !== null) { - $('#imgtip2_img').attr('src', config.imgPathURL + config.tipImgs[2] + cacheDefeat); + cache.maxValue = Math.max(nextHighest(cache.value, 2), gaugeGlobals.rainScaleDefMaxIn); } + cache.scaleDecimals = cache.maxValue < 1 ? 2 : 1; } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + if (cache.maxValue !== ssGauge.getMaxValue()) { + // Gauge scale is too low, increase it. + // First set the pointer back to zero so we get a nice animation + ssGauge.setValue(0); + // and redraw the gauge with the new scale + ssGauge.setFractionalScaleDecimals(cache.scaleDecimals); + ssGauge.setMaxValue(cache.maxValue); + } + ssGauge.setValueAnimated(cache.value); + + if (ddimgtooltip.showTips) { + // update tooltip + $('#imgtip2_txt').html(strings.LastRain_info + ': ' + data.LastRained); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[2] !== null) { + $('#imgtip2_img').attr('src', config.imgPathURL + config.tipImgs[2] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), + } // End of init() - // - // Singleton for the Rainfall Rate Gauge - // - singleRRate = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), - function init() { - var params = $.extend(true, {}, commonParams); + // + // Singleton for the Rainfall Rate Gauge + // + singleRRate = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // define rain rate gauge start values - cache.maxMeasured = 0; - cache.maxValue = gaugeGlobals.rainRateScaleDefMaxmm; - cache.value = 0.0001; - cache.title = strings.rrate_title; - cache.lcdDecimals = 1; - cache.scaleDecimals = 0; - cache.labelNumberFormat = gaugeGlobals.labelFormat; - cache.sections = createRainRateSections(true); + function init() { + var params = $.extend(true, {}, commonParams); - // create rain rate radial gauge - if ($('#canvas_rrate').length) { - params.size = Math.ceil($('#canvas_rrate').width() * config.gaugeScaling); - params.section = cache.sections; - params.maxValue = cache.maxValue; - params.thresholdVisible = false; - params.maxMeasuredValueVisible = true; - params.titleString = cache.title; - params.unitString = data.rainunit + '/h'; - params.lcdDecimals = cache.lcdDecimals; - params.labelNumberFormat = cache.labelNumberFormat; - params.fractionalScaleDecimals = cache.scaleDecimals; - params.niceScale = false; + // define rain rate gauge start values + cache.maxMeasured = 0; + cache.maxValue = gaugeGlobals.rainRateScaleDefMaxmm; + cache.value = 0.0001; + cache.title = strings.rrate_title; + cache.lcdDecimals = 1; + cache.scaleDecimals = 0; + cache.labelNumberFormat = gaugeGlobals.labelFormat; + cache.sections = createRainRateSections(true); - ssGauge = new steelseries.Radial('canvas_rrate', params); - ssGauge.setMaxMeasuredValue(cache.maxMeasured); - ssGauge.setValue(cache.value); + // create rain rate radial gauge + if ($('#canvas_rrate').length) { + params.size = Math.ceil($('#canvas_rrate').width() * config.gaugeScaling); + params.section = cache.sections; + params.maxValue = cache.maxValue; + params.thresholdVisible = false; + params.maxMeasuredValueVisible = true; + params.titleString = cache.title; + params.unitString = data.rainunit + '/h'; + params.lcdDecimals = cache.lcdDecimals; + params.labelNumberFormat = cache.labelNumberFormat; + params.fractionalScaleDecimals = cache.scaleDecimals; + params.niceScale = false; - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_rrate').css({width: params.size + 'px', height: params.size + 'px'}); - } + ssGauge = new steelseries.Radial('canvas_rrate', params); + ssGauge.setMaxMeasuredValue(cache.maxMeasured); + ssGauge.setValue(cache.value); - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_rrate').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_rrate').css({ width: params.size + 'px', height: params.size + 'px' }); } - function update() { - var tip; + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_rrate').css(gaugeShadow(params.size)); + } - cache.value = extractDecimal(data.rrate); - cache.maxMeasured = extractDecimal(data.rrateTM); - cache.overallMax = Math.max(cache.maxMeasured, cache.value); // workaround for VWS bug, not supplying correct max value today + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } - if (data.rainunit === 'mm') { // 10, 20, 30... + function update() { + var tip; + + cache.value = extractDecimal(data.rrate); + cache.maxMeasured = extractDecimal(data.rrateTM); + cache.overallMax = Math.max(cache.maxMeasured, cache.value); // workaround for VWS bug, not supplying correct max value today + + if (data.rainunit === 'mm') { // 10, 20, 30... + cache.maxValue = nextHighest(cache.overallMax, 10); + } else { + // inches 0.5, 1.0, 2.0, 3.0 ... 10, 20, 30... + if (cache.overallMax <= 0.5) { + cache.maxValue = 0.5; + } else if (cache.overallMax <= 10) { + cache.maxValue = nextHighest(cache.overallMax, 1); + } else { cache.maxValue = nextHighest(cache.overallMax, 10); - } else { - // inches 0.5, 1.0, 2.0, 3.0 ... 10, 20, 30... - if (cache.overallMax <= 0.5) { - cache.maxValue = 0.5; - } else if (cache.overallMax <= 10) { - cache.maxValue = nextHighest(cache.overallMax, 1); - } else { - cache.maxValue = nextHighest(cache.overallMax, 10); - } - cache.scaleDecimals = cache.maxValue < 1 ? 2 : (cache.maxValue < 7 ? 1 : 0); - } - - if (cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setValue(0); - ssGauge.setFractionalScaleDecimals(cache.scaleDecimals); - ssGauge.setMaxValue(cache.maxValue); - } - - ssGauge.setValueAnimated(cache.value); - ssGauge.setMaxMeasuredValue(cache.maxMeasured); - - if (ddimgtooltip.showTips) { - // update tooltip - tip = strings.rrate_info + ':
' + - '- ' + strings.maximum_info + ': ' + data.rrateTM + ' ' + data.rainunit + '/h ' + strings.at + ' ' + data.TrrateTM + - ' | ' + strings.max_hour_info + ': ' + extractDecimal(data.hourlyrainTH) + ' ' + data.rainunit + ' ' + - strings.at + ' ' + data.ThourlyrainTH; - $('#imgtip3_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[3] !== null) { - $('#imgtip3_img').attr('src', config.imgPathURL + config.tipImgs[3] + cacheDefeat); } + cache.scaleDecimals = cache.maxValue < 1 ? 2 : (cache.maxValue < 7 ? 1 : 0); } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + if (cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setValue(0); + ssGauge.setFractionalScaleDecimals(cache.scaleDecimals); + ssGauge.setMaxValue(cache.maxValue); + } + + ssGauge.setValueAnimated(cache.value); + ssGauge.setMaxMeasuredValue(cache.maxMeasured); + + if (ddimgtooltip.showTips) { + // update tooltip + tip = strings.rrate_info + ':
' + + '- ' + strings.maximum_info + ': ' + data.rrateTM + ' ' + data.rainunit + '/h ' + strings.at + ' ' + data.TrrateTM + + ' | ' + strings.max_hour_info + ': ' + extractDecimal(data.hourlyrainTH) + ' ' + data.rainunit + ' ' + + strings.at + ' ' + data.ThourlyrainTH; + $('#imgtip3_txt').html(tip); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[3] !== null) { + $('#imgtip3_img').attr('src', config.imgPathURL + config.tipImgs[3] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), + } // End of init() - // - // Singleton for the Humidity Gauge - // - singleHum = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), - function init() { - var params = $.extend(true, {}, commonParams); + // + // Singleton for the Humidity Gauge + // + singleHum = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // define humidity gauge start values - cache.areas = []; - cache.value = 0.0001; - cache.title = strings.hum_title_out; - cache.selected = 'out'; + function init() { + var params = $.extend(true, {}, commonParams); - // create humidity radial gauge - if ($('#canvas_hum').length) { - params.size = Math.ceil($('#canvas_hum').width() * config.gaugeScaling); - params.section = [ - steelseries.Section(0, 20, 'rgba(255,255,0,0.3)'), - steelseries.Section(20, 80, 'rgba(0,255,0,0.3)'), - steelseries.Section(80, 100, 'rgba(255,0,0,0.3)') - ]; - params.area = cache.areas; - params.maxValue = 100; - params.thresholdVisible = false; - params.titleString = cache.title; - params.unitString = 'RH%'; + // define humidity gauge start values + cache.areas = []; + cache.value = 0.0001; + cache.title = strings.hum_title_out; + cache.selected = 'out'; - ssGauge = new steelseries.Radial('canvas_hum', params); - ssGauge.setValue(cache.value); + // create humidity radial gauge + if ($('#canvas_hum').length) { + params.size = Math.ceil($('#canvas_hum').width() * config.gaugeScaling); + params.section = [ + steelseries.Section(0, 20, 'rgba(255,255,0,0.3)'), + steelseries.Section(20, 80, 'rgba(0,255,0,0.3)'), + steelseries.Section(80, 100, 'rgba(255,0,0,0.3)') + ]; + params.area = cache.areas; + params.maxValue = 100; + params.thresholdVisible = false; + params.titleString = cache.title; + params.unitString = 'RH%'; - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_hum').css({width: params.size + 'px', height: params.size + 'px'}); - } + ssGauge = new steelseries.Radial('canvas_hum', params); + ssGauge.setValue(cache.value); - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_hum').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_hum').css({ width: params.size + 'px', height: params.size + 'px' }); } - function update() { - var radio; - // Argument length === 2 when called from event handler - if (arguments.length === 1) { - radio = arguments[0]; - } + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_hum').css(gaugeShadow(params.size)); + } - // if rad isn't specified, just use existing value - var sel = (typeof radio === 'undefined' ? cache.selected : radio.value), - tip; + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } - if (sel === 'out') { - cache.value = extractDecimal(data.hum); - cache.areas = [steelseries.Section(+extractDecimal(data.humTL), +extractDecimal(data.humTH), gaugeGlobals.minMaxArea)]; - cache.title = strings.hum_title_out; - cache.popupImg = 0; + function update() { + var radio; + // Argument length === 2 when called from event handler + if (arguments.length === 1) { + radio = arguments[0]; + } + + // if rad isn't specified, just use existing value + var sel = (typeof radio === 'undefined' ? cache.selected : radio.value), + tip; + + if (sel === 'out') { + cache.value = extractDecimal(data.hum); + cache.areas = [steelseries.Section(+extractDecimal(data.humTL), +extractDecimal(data.humTH), gaugeGlobals.minMaxArea)]; + cache.title = strings.hum_title_out; + cache.popupImg = 0; + } else { + cache.value = extractDecimal(data.inhum); + if (data.inhumTL && data.inhumTH) { + cache.areas = [steelseries.Section(+extractDecimal(data.inhumTL), +extractDecimal(data.inhumTH), gaugeGlobals.minMaxArea)]; } else { - cache.value = extractDecimal(data.inhum); - if (data.inhumTL && data.inhumTH) { - cache.areas = [steelseries.Section(+extractDecimal(data.inhumTL), +extractDecimal(data.inhumTH), gaugeGlobals.minMaxArea)]; - } else { - cache.areas = []; - } - cache.title = strings.hum_title_in; - cache.popupImg = 1; + cache.areas = []; } + cache.title = strings.hum_title_in; + cache.popupImg = 1; + } - if (cache.selected !== sel) { - cache.selected = sel; - // Change gauge title - ssGauge.setTitleString(cache.title); - if (config.showPopupGraphs && config.tipImgs[4][cache.popupImg] !== null) { - var cacheDefeat = '?' + $('#imgtip4_img').attr('src').split('?')[1]; - $('#imgtip4_img').attr('src', config.imgPathURL + config.tipImgs[4][cache.popupImg] + cacheDefeat); - } - } - - ssGauge.setArea(cache.areas); - ssGauge.setValueAnimated(cache.value); - - if (ddimgtooltip.showTips) { - // update tooltip - if (cache.selected === 'out') { - tip = strings.hum_out_info + ':' + - '
' + - '- ' + strings.minimum_info + ': ' + extractDecimal(data.humTL) + '% ' + strings.at + ' ' + data.ThumTL + - ' | ' + strings.maximum_info + ': ' + extractDecimal(data.humTH) + '% ' + strings.at + ' ' + data.ThumTH; - } else if (data.inhumTL && data.inhumTH) { - // we have indoor high/low data - tip = strings.hum_in_info + ':' + - '
' + - '- ' + strings.minimum_info + ': ' + extractDecimal(data.inhumTL) + '% ' + strings.at + ' ' + data.TinhumTL + - ' | ' + strings.maximum_info + ': ' + extractDecimal(data.inhumTH) + '% ' + strings.at + ' ' + data.TinhumTH; - } else { - // no indoor high/low data - tip = strings.hum_in_info + ': ' + extractDecimal(data.inhum) + '%'; - } - $('#imgtip4_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[4][cache.popupImg] !== null) { + if (cache.selected !== sel) { + cache.selected = sel; + // Change gauge title + ssGauge.setTitleString(cache.title); + if (config.showPopupGraphs && config.tipImgs[4][cache.popupImg] !== null) { + var cacheDefeat = '?' + $('#imgtip4_img').attr('src').split('?')[1]; $('#imgtip4_img').attr('src', config.imgPathURL + config.tipImgs[4][cache.popupImg] + cacheDefeat); } } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + ssGauge.setArea(cache.areas); + ssGauge.setValueAnimated(cache.value); - return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } - }; - })(), - - // - // Singleton for the Barometer Gauge - // - singleBaro = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters - - function init() { - var params = $.extend(true, {}, commonParams); - - // define pressure/barometer gauge start values - cache.sections = []; - cache.areas = []; - cache.minValue = gaugeGlobals.baroScaleDefMinhPa; - cache.maxValue = gaugeGlobals.baroScaleDefMaxhPa; - cache.value = cache.minValue + 0.0001; - cache.title = strings.baro_title; - cache.lcdDecimals = 1; - cache.scaleDecimals = 0; - cache.labelNumberFormat = gaugeGlobals.labelFormat; - - // create pressure/barometric radial gauge - if ($('#canvas_baro').length) { - params.size = Math.ceil($('#canvas_baro').width() * config.gaugeScaling); - params.section = cache.sections; - params.area = cache.areas; - params.minValue = cache.minValue; - params.maxValue = cache.maxValue; - params.niceScale = false; - params.thresholdVisible = false; - params.titleString = cache.title; - params.unitString = data.pressunit; - params.lcdDecimals = cache.lcdDecimals; - params.trendVisible = gaugeGlobals.pressureTrendVisible; - params.labelNumberFormat = cache.labelNumberFormat; - params.fractionalScaleDecimals = cache.scaleDecimals; - - ssGauge = new steelseries.Radial('canvas_baro', params); - ssGauge.setValue(cache.value); - - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_baro').css({width: params.size + 'px', height: params.size + 'px'}); - } - - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_baro').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; - } - - function update() { - var tip, t1, dps; - - cache.recLow = +extractDecimal(data.pressL); - cache.recHigh = +extractDecimal(data.pressH); - cache.todayLow = +extractDecimal(data.pressTL); - cache.todayHigh = +extractDecimal(data.pressTH); - cache.value = +extractDecimal(data.press); - // Convert the WD change over 3 hours to an hourly rate - cache.trendVal = +extractDecimal(data.presstrendval) / (config.weatherProgram === 2 ? 3 : 1); - - if (data.pressunit === 'hPa' || data.pressunit === 'mb') { - // default min range 990-1030 - steps of 10 hPa - cache.minValue = Math.min(nextLowest(cache.recLow - 2, 10), gaugeGlobals.baroScaleDefMinhPa); - cache.maxValue = Math.max(nextHighest(cache.recHigh + 2, 10), gaugeGlobals.baroScaleDefMaxhPa); - dps = 1; // 1 decimal place - } else if (data.pressunit === 'kPa') { - // default min range 99-105 - steps of 1 kPa - cache.minValue = Math.min(nextLowest(cache.recLow - 0.2, 1), gaugeGlobals.baroScaleDefMinkPa); - cache.maxValue = Math.max(nextHighest(cache.recHigh + 0.2, 1), gaugeGlobals.baroScaleDefMaxkPa); - dps = 2; - } else { - // inHg: default min range 29.5-30.5 - steps of 0.5 inHg - cache.minValue = Math.min(nextLowest(cache.recLow - 0.1, 0.5), gaugeGlobals.baroScaleDefMininHg); - cache.maxValue = Math.max(nextHighest(cache.recHigh + 0.1, 0.5), gaugeGlobals.baroScaleDefMaxinHg); - dps = 3; - } - cache.trendValRnd = cache.trendVal.toFixed(dps); - cache.todayLowRnd = cache.todayLow.toFixed(dps); - cache.todayHighRnd = cache.todayHigh.toFixed(dps); - - if (cache.minValue !== ssGauge.getMinValue() || cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setMinValue(cache.minValue); - ssGauge.setMaxValue(cache.maxValue); - ssGauge.setValue(cache.minValue); - } - if (cache.recHigh === cache.todayHigh && cache.recLow === cache.todayLow) { - // VWS does not provide record hi/lo values - cache.sections = []; - cache.areas = [steelseries.Section(cache.todayLow, cache.todayHigh, gaugeGlobals.minMaxArea)]; - } else { - cache.sections = [ - steelseries.Section(cache.minValue, cache.recLow, 'rgba(255,0,0,0.5)'), - steelseries.Section(cache.recHigh, cache.maxValue, 'rgba(255,0,0,0.5)') - ]; - cache.areas = [ - steelseries.Section(cache.minValue, cache.recLow, 'rgba(255,0,0,0.5)'), - steelseries.Section(cache.recHigh, cache.maxValue, 'rgba(255,0,0,0.5)'), - steelseries.Section(cache.todayLow, cache.todayHigh, gaugeGlobals.minMaxArea) - ]; - } - - if (gaugeGlobals.pressureTrendVisible) { - // Use the baroTrend rather than simple arithmetic test - steady is more/less than zero! - t1 = baroTrend(cache.trendVal, data.pressunit, false); - if (t1 === -9999) { - // trend value isn't currently available - cache.trend = steelseries.TrendState.OFF; - } else if (t1 > 0) { - cache.trend = steelseries.TrendState.UP; - } else if (t1 < 0) { - cache.trend = steelseries.TrendState.DOWN; - } else { - cache.trend = steelseries.TrendState.STEADY; - } - ssGauge.setTrend(cache.trend); - } - - ssGauge.setArea(cache.areas); - ssGauge.setSection(cache.sections); - ssGauge.setValueAnimated(cache.value); - - if (ddimgtooltip.showTips) { - // update tooltip - tip = strings.baro_info + ':' + + if (ddimgtooltip.showTips) { + // update tooltip + if (cache.selected === 'out') { + tip = strings.hum_out_info + ':' + '
' + - '- ' + strings.minimum_info + ': ' + cache.todayLowRnd + ' ' + data.pressunit + ' ' + strings.at + ' ' + data.TpressTL + - ' | ' + strings.maximum_info + ': ' + cache.todayHighRnd + ' ' + data.pressunit + ' ' + strings.at + ' ' + data.TpressTH; - if (cache.trendVal !== -9999) { - tip += '
' + - '- ' + strings.baro_trend_info + ': ' + baroTrend(cache.trendVal, data.pressunit, true) + ' ' + - (cache.trendValRnd > 0 ? '+' : '') + cache.trendValRnd + ' ' + data.pressunit + '/h'; - } - $('#imgtip5_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[5] !== null) { - $('#imgtip5_img').attr('src', config.imgPathURL + config.tipImgs[5] + cacheDefeat); + '- ' + strings.minimum_info + ': ' + extractDecimal(data.humTL) + '% ' + strings.at + ' ' + data.ThumTL + + ' | ' + strings.maximum_info + ': ' + extractDecimal(data.humTH) + '% ' + strings.at + ' ' + data.ThumTH; + } else if (data.inhumTL && data.inhumTH) { + // we have indoor high/low data + tip = strings.hum_in_info + ':' + + '
' + + '- ' + strings.minimum_info + ': ' + extractDecimal(data.inhumTL) + '% ' + strings.at + ' ' + data.TinhumTL + + ' | ' + strings.maximum_info + ': ' + extractDecimal(data.inhumTH) + '% ' + strings.at + ' ' + data.TinhumTH; + } else { + // no indoor high/low data + tip = strings.hum_in_info + ': ' + extractDecimal(data.inhum) + '%'; } + $('#imgtip4_txt').html(tip); } + } // End of update() - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[4][cache.popupImg] !== null) { + $('#imgtip4_img').attr('src', config.imgPathURL + config.tipImgs[4][cache.popupImg] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), + } // End of init() - // - // Singleton for the Wind Speed Gauge - // - singleWind = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), - function init() { - var params = $.extend(true, {}, commonParams); + // + // Singleton for the Barometer Gauge + // + singleBaro = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // define wind gauge start values - cache.maxValue = gaugeGlobals.windScaleDefMaxKph; - cache.areas = []; - cache.maxMeasured = 0; - cache.value = 0.0001; - cache.title = strings.wind_title; + function init() { + var params = $.extend(true, {}, commonParams); - // create wind speed radial gauge - if ($('#canvas_wind').length) { - params.size = Math.ceil($('#canvas_wind').width() * config.gaugeScaling); - params.area = cache.areas; - params.maxValue = cache.maxValue; - params.niceScale = false; - params.thresholdVisible = false; - params.maxMeasuredValueVisible = true; - params.titleString = cache.title; - params.unitString = data.windunit; + // define pressure/barometer gauge start values + cache.sections = []; + cache.areas = []; + cache.minValue = gaugeGlobals.baroScaleDefMinhPa; + cache.maxValue = gaugeGlobals.baroScaleDefMaxhPa; + cache.value = cache.minValue + 0.0001; + cache.title = strings.baro_title; + cache.lcdDecimals = 1; + cache.scaleDecimals = 0; + cache.labelNumberFormat = gaugeGlobals.labelFormat; - ssGauge = new steelseries.Radial('canvas_wind', params); - ssGauge.setMaxMeasuredValue(cache.maxMeasured); - ssGauge.setValue(cache.value); + // create pressure/barometric radial gauge + if ($('#canvas_baro').length) { + params.size = Math.ceil($('#canvas_baro').width() * config.gaugeScaling); + params.section = cache.sections; + params.area = cache.areas; + params.minValue = cache.minValue; + params.maxValue = cache.maxValue; + params.niceScale = false; + params.thresholdVisible = false; + params.titleString = cache.title; + params.unitString = data.pressunit; + params.lcdDecimals = cache.lcdDecimals; + params.trendVisible = gaugeGlobals.pressureTrendVisible; + params.labelNumberFormat = cache.labelNumberFormat; + params.fractionalScaleDecimals = cache.scaleDecimals; - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_wind').css({width: params.size + 'px', height: params.size + 'px'}); - } + ssGauge = new steelseries.Radial('canvas_baro', params); + ssGauge.setValue(cache.value); - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_wind').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_baro').css({ width: params.size + 'px', height: params.size + 'px' }); } - function update() { - var tip; + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_baro').css(gaugeShadow(params.size)); + } - cache.value = extractDecimal(data.wlatest); - cache.average = extractDecimal(data.wspeed); - cache.gust = extractDecimal(data.wgust); - cache.maxGustToday = extractDecimal(data.wgustTM); - cache.maxAvgToday = extractDecimal(data.windTM); + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } - switch (data.windunit) { + function update() { + var tip, t1, dps; + + cache.recLow = +extractDecimal(data.pressL); + cache.recHigh = +extractDecimal(data.pressH); + cache.todayLow = +extractDecimal(data.pressTL); + cache.todayHigh = +extractDecimal(data.pressTH); + cache.value = +extractDecimal(data.press); + // Convert the WD change over 3 hours to an hourly rate + cache.trendVal = +extractDecimal(data.presstrendval) / (config.weatherProgram === 2 ? 3 : 1); + + if (data.pressunit === 'hPa' || data.pressunit === 'mb') { + // default min range 990-1030 - steps of 10 hPa + cache.minValue = Math.min(nextLowest(cache.recLow - 2, 10), gaugeGlobals.baroScaleDefMinhPa); + cache.maxValue = Math.max(nextHighest(cache.recHigh + 2, 10), gaugeGlobals.baroScaleDefMaxhPa); + dps = 1; // 1 decimal place + } else if (data.pressunit === 'kPa') { + // default min range 99-105 - steps of 1 kPa + cache.minValue = Math.min(nextLowest(cache.recLow - 0.2, 1), gaugeGlobals.baroScaleDefMinkPa); + cache.maxValue = Math.max(nextHighest(cache.recHigh + 0.2, 1), gaugeGlobals.baroScaleDefMaxkPa); + dps = 2; + } else { + // inHg: default min range 29.5-30.5 - steps of 0.5 inHg + cache.minValue = Math.min(nextLowest(cache.recLow - 0.1, 0.5), gaugeGlobals.baroScaleDefMininHg); + cache.maxValue = Math.max(nextHighest(cache.recHigh + 0.1, 0.5), gaugeGlobals.baroScaleDefMaxinHg); + dps = 3; + } + cache.trendValRnd = cache.trendVal.toFixed(dps); + cache.todayLowRnd = cache.todayLow.toFixed(dps); + cache.todayHighRnd = cache.todayHigh.toFixed(dps); + + if (cache.minValue !== ssGauge.getMinValue() || cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setMinValue(cache.minValue); + ssGauge.setMaxValue(cache.maxValue); + ssGauge.setValue(cache.minValue); + } + if (cache.recHigh === cache.todayHigh && cache.recLow === cache.todayLow) { + // VWS does not provide record hi/lo values + cache.sections = []; + cache.areas = [steelseries.Section(cache.todayLow, cache.todayHigh, gaugeGlobals.minMaxArea)]; + } else { + cache.sections = [ + steelseries.Section(cache.minValue, cache.recLow, 'rgba(255,0,0,0.5)'), + steelseries.Section(cache.recHigh, cache.maxValue, 'rgba(255,0,0,0.5)') + ]; + cache.areas = [ + steelseries.Section(cache.minValue, cache.recLow, 'rgba(255,0,0,0.5)'), + steelseries.Section(cache.recHigh, cache.maxValue, 'rgba(255,0,0,0.5)'), + steelseries.Section(cache.todayLow, cache.todayHigh, gaugeGlobals.minMaxArea) + ]; + } + + if (gaugeGlobals.pressureTrendVisible) { + // Use the baroTrend rather than simple arithmetic test - steady is more/less than zero! + t1 = baroTrend(cache.trendVal, data.pressunit, false); + if (t1 === -9999) { + // trend value isn't currently available + cache.trend = steelseries.TrendState.OFF; + } else if (t1 > 0) { + cache.trend = steelseries.TrendState.UP; + } else if (t1 < 0) { + cache.trend = steelseries.TrendState.DOWN; + } else { + cache.trend = steelseries.TrendState.STEADY; + } + ssGauge.setTrend(cache.trend); + } + + ssGauge.setArea(cache.areas); + ssGauge.setSection(cache.sections); + ssGauge.setValueAnimated(cache.value); + + if (ddimgtooltip.showTips) { + // update tooltip + tip = strings.baro_info + ':' + + '
' + + '- ' + strings.minimum_info + ': ' + cache.todayLowRnd + ' ' + data.pressunit + ' ' + strings.at + ' ' + data.TpressTL + + ' | ' + strings.maximum_info + ': ' + cache.todayHighRnd + ' ' + data.pressunit + ' ' + strings.at + ' ' + data.TpressTH; + if (cache.trendVal !== -9999) { + tip += '
' + + '- ' + strings.baro_trend_info + ': ' + baroTrend(cache.trendVal, data.pressunit, true) + ' ' + + (cache.trendValRnd > 0 ? '+' : '') + cache.trendValRnd + ' ' + data.pressunit + '/h'; + } + $('#imgtip5_txt').html(tip); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[5] !== null) { + $('#imgtip5_img').attr('src', config.imgPathURL + config.tipImgs[5] + cacheDefeat); + } + } + + return { + data: cache, + update: update, + gauge: ssGauge + }; + } // End of init() + + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), + + // + // Singleton for the Wind Speed Gauge + // + singleWind = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters + + function init() { + var params = $.extend(true, {}, commonParams); + + // define wind gauge start values + cache.maxValue = gaugeGlobals.windScaleDefMaxKph; + cache.areas = []; + cache.maxMeasured = 0; + cache.value = 0.0001; + cache.title = strings.wind_title; + + // create wind speed radial gauge + if ($('#canvas_wind').length) { + params.size = Math.ceil($('#canvas_wind').width() * config.gaugeScaling); + params.area = cache.areas; + params.maxValue = cache.maxValue; + params.niceScale = false; + params.thresholdVisible = false; + params.maxMeasuredValueVisible = true; + params.titleString = cache.title; + params.unitString = data.windunit; + + ssGauge = new steelseries.Radial('canvas_wind', params); + ssGauge.setMaxMeasuredValue(cache.maxMeasured); + ssGauge.setValue(cache.value); + + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_wind').css({ width: params.size + 'px', height: params.size + 'px' }); + } + + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_wind').css(gaugeShadow(params.size)); + } + + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } + + function update() { + var tip; + + cache.value = extractDecimal(data.wlatest); + cache.average = extractDecimal(data.wspeed); + cache.gust = extractDecimal(data.wgust); + cache.maxGustToday = extractDecimal(data.wgustTM); + cache.maxAvgToday = extractDecimal(data.windTM); + + switch (data.windunit) { case 'mph': case 'kts': cache.maxValue = Math.max(nextHighest(cache.maxGustToday, 10), gaugeGlobals.windScaleDefMaxMph); @@ -1804,129 +1805,129 @@ gauges = (function () { break; default: cache.maxValue = Math.max(nextHighest(cache.maxGustToday, 20), gaugeGlobals.windScaleDefMaxKmh); - } - cache.areas = [ - steelseries.Section(0, +cache.average, gaugeGlobals.windAvgArea), - steelseries.Section(+cache.average, +cache.gust, gaugeGlobals.minMaxArea) - ]; - if (cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setValue(0); - ssGauge.setMaxValue(cache.maxValue); - } - - ssGauge.setArea(cache.areas); - ssGauge.setMaxMeasuredValue(cache.maxGustToday); - ssGauge.setValueAnimated(cache.value); - - if (ddimgtooltip.showTips) { - // update tooltip - tip = strings.tenminavgwind_info + ': ' + cache.average + ' ' + data.windunit + ' | ' + - strings.maxavgwind_info + ': ' + cache.maxAvgToday + ' ' + data.windunit + '
' + - strings.tenmingust_info + ': ' + cache.gust + ' ' + data.windunit + ' | ' + - strings.maxgust_info + ': ' + cache.maxGustToday + ' ' + data.windunit + ' ' + - strings.at + ' ' + data.TwgustTM + ' ' + strings.bearing_info + ': ' + data.bearingTM + - (isNaN(parseFloat(data.bearingTM)) ? '' : '° (' + getord(+data.bearingTM) + ')'); - $('#imgtip6_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[6] !== null) { - $('#imgtip6_img').attr('src', config.imgPathURL + config.tipImgs[6] + cacheDefeat); - } + } + cache.areas = [ + steelseries.Section(0, +cache.average, gaugeGlobals.windAvgArea), + steelseries.Section(+cache.average, +cache.gust, gaugeGlobals.minMaxArea) + ]; + if (cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setValue(0); + ssGauge.setMaxValue(cache.maxValue); } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + ssGauge.setArea(cache.areas); + ssGauge.setMaxMeasuredValue(cache.maxGustToday); + ssGauge.setValueAnimated(cache.value); + + if (ddimgtooltip.showTips) { + // update tooltip + tip = strings.tenminavgwind_info + ': ' + cache.average + ' ' + data.windunit + ' | ' + + strings.maxavgwind_info + ': ' + cache.maxAvgToday + ' ' + data.windunit + '
' + + strings.tenmingust_info + ': ' + cache.gust + ' ' + data.windunit + ' | ' + + strings.maxgust_info + ': ' + cache.maxGustToday + ' ' + data.windunit + ' ' + + strings.at + ' ' + data.TwgustTM + ' ' + strings.bearing_info + ': ' + data.bearingTM + + (isNaN(parseFloat(data.bearingTM)) ? '' : '° (' + getord(+data.bearingTM) + ')'); + $('#imgtip6_txt').html(tip); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[6] !== null) { + $('#imgtip6_img').attr('src', config.imgPathURL + config.tipImgs[6] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), // End of singleWind() + } // End of init() - // - // Singleton for the Wind Direction Gauge - // - singleDir = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), // End of singleWind() - function init() { - var params = $.extend(true, {}, commonParams); + // + // Singleton for the Wind Direction Gauge + // + singleDir = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // define wind direction gauge start values - cache.valueLatest = 0; - cache.valueAverage = 0; - cache.titles = [strings.latest_web, strings.tenminavg_web]; + function init() { + var params = $.extend(true, {}, commonParams); - // create wind direction/compass radial gauge - if ($('#canvas_dir').length) { - params.size = Math.ceil($('#canvas_dir').width() * config.gaugeScaling); - params.pointerTypeLatest = gaugeGlobals.pointer; // default TYPE8, - params.pointerTypeAverage = gaugeGlobals.dirAvgPointer; // default TYPE8 - params.pointerColorAverage = gaugeGlobals.dirAvgPointerColour; - params.degreeScale = true; // Show degree scale rather than ordinal directions - params.pointSymbols = strings.compass; - params.roseVisible = false; - params.lcdTitleStrings = cache.titles; - params.useColorLabels = false; + // define wind direction gauge start values + cache.valueLatest = 0; + cache.valueAverage = 0; + cache.titles = [strings.latest_web, strings.tenminavg_web]; - ssGauge = new steelseries.WindDirection('canvas_dir', params); - ssGauge.setValueAverage(+cache.valueAverage); - ssGauge.setValueLatest(+cache.valueLatest); + // create wind direction/compass radial gauge + if ($('#canvas_dir').length) { + params.size = Math.ceil($('#canvas_dir').width() * config.gaugeScaling); + params.pointerTypeLatest = gaugeGlobals.pointer; // default TYPE8, + params.pointerTypeAverage = gaugeGlobals.dirAvgPointer; // default TYPE8 + params.pointerColorAverage = gaugeGlobals.dirAvgPointerColour; + params.degreeScale = true; // Show degree scale rather than ordinal directions + params.pointSymbols = strings.compass; + params.roseVisible = false; + params.lcdTitleStrings = cache.titles; + params.useColorLabels = false; - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_dir').css({width: params.size + 'px', height: params.size + 'px'}); - } + ssGauge = new steelseries.WindDirection('canvas_dir', params); + ssGauge.setValueAverage(+cache.valueAverage); + ssGauge.setValueLatest(+cache.valueLatest); - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_dir').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_dir').css({ width: params.size + 'px', height: params.size + 'px' }); } - function update() { - var windSpd, windGst, range, tip, i, - rosePoints = 0, - roseMax = 0, - roseSectionAngle = 0, - roseAreas = []; + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_dir').css(gaugeShadow(params.size)); + } - cache.valueLatest = extractInteger(data.bearing); - cache.valueAverage = extractInteger(data.avgbearing); - cache.bearingFrom = extractInteger(data.BearingRangeFrom10); - cache.bearingTo = extractInteger(data.BearingRangeTo10); + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } - ssGauge.setValueAnimatedAverage(+cache.valueAverage); - if (cache.valueAverage === 0) { - cache.valueLatest = 0; - } - ssGauge.setValueAnimatedLatest(+cache.valueLatest); + function update() { + var windSpd, windGst, range, tip, i, + rosePoints = 0, + roseMax = 0, + roseSectionAngle = 0, + roseAreas = []; - if (config.showWindVariation) { - windSpd = +extractDecimal(data.wspeed); - windGst = +extractDecimal(data.wgust); - switch (data.windunit.toLowerCase()) { + cache.valueLatest = extractInteger(data.bearing); + cache.valueAverage = extractInteger(data.avgbearing); + cache.bearingFrom = extractInteger(data.BearingRangeFrom10); + cache.bearingTo = extractInteger(data.BearingRangeTo10); + + ssGauge.setValueAnimatedAverage(+cache.valueAverage); + if (cache.valueAverage === 0) { + cache.valueLatest = 0; + } + ssGauge.setValueAnimatedLatest(+cache.valueLatest); + + if (config.showWindVariation) { + windSpd = +extractDecimal(data.wspeed); + windGst = +extractDecimal(data.wgust); + switch (data.windunit.toLowerCase()) { case 'mph': cache.avgKnots = 0.868976242 * windSpd; cache.gstKnots = 0.868976242 * windGst; @@ -1944,181 +1945,387 @@ gauges = (function () { cache.gstKnots = 0.539956803 * windGst; break; // no default - } - cache.avgKnots = Math.round(cache.avgKnots); - cache.gstKnots = Math.round(cache.gstKnots); - if (config.showWindMetar) { - ssGauge.VRB = ' - METAR: ' + ('0' + data.avgbearing).slice(-3) + ('0' + cache.avgKnots).slice(-2) + - 'G' + ('0' + cache.gstKnots).slice(-2) + 'KT '; - } else { - ssGauge.VRB = ''; - } - if (windSpd > 0) { - // If variation less than 60 degrees, then METAR = Steady - // Unless range = 0 and from/to direction = avg + 180 - range = (+cache.bearingTo < +cache.bearingFrom ? 360 + (+cache.bearingTo) : +cache.bearingTo) - (+cache.bearingFrom); - - if (cache.avgKnots < 3) { // Europe uses 3kts, USA 6kts as the threshold - if (config.showRoseOnDirGauge) { - ssGauge.setSection([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.windVariationSector)]); - ssGauge.setSection([]); - } else { - ssGauge.setSection([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.minMaxArea)]); - ssGauge.setArea([]); - } - } else if (config.showRoseOnDirGauge) { - ssGauge.setSection([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.windVariationSector)]); - } else { - ssGauge.setSection([]); - ssGauge.setArea([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.minMaxArea)]); - } - if (config.showWindMetar) { - if ((range < 60 && range > 0) || range === 0 && cache.bearingFrom === cache.valueAverage) { - ssGauge.VRB += ' STDY'; - } else if (cache.avgKnots < 3) { // Europe uses 3kts, USA 6kts as the threshold - ssGauge.VRB += ' VRB'; - } else { - ssGauge.VRB += ' ' + cache.bearingFrom + 'V' + cache.bearingTo; - } - } - } else { - // Zero wind speed, calm - if (config.showWindMetar) { - ssGauge.VRB = ' - METAR: 00000KT'; - } - ssGauge.setSection([]); - if (!config.showRoseOnDirGauge) { - ssGauge.setArea([]); - } - } + } + cache.avgKnots = Math.round(cache.avgKnots); + cache.gstKnots = Math.round(cache.gstKnots); + if (config.showWindMetar) { + ssGauge.VRB = ' - METAR: ' + ('0' + data.avgbearing).slice(-3) + ('0' + cache.avgKnots).slice(-2) + + 'G' + ('0' + cache.gstKnots).slice(-2) + 'KT '; } else { ssGauge.VRB = ''; } + if (windSpd > 0) { + // If variation less than 60 degrees, then METAR = Steady + // Unless range = 0 and from/to direction = avg + 180 + range = (+cache.bearingTo < +cache.bearingFrom ? 360 + (+cache.bearingTo) : +cache.bearingTo) - (+cache.bearingFrom); - // optional rose data on direction gauge - if (config.showRoseOnDirGauge && data.WindRoseData) { - // Process rose data - rosePoints = data.WindRoseData.length; - roseSectionAngle = 360 / rosePoints; - // Find total for all directions - for (i = 0; i < rosePoints; i++) { - roseMax = Math.max(roseMax, data.WindRoseData[i]); + if (cache.avgKnots < 3) { // Europe uses 3kts, USA 6kts as the threshold + if (config.showRoseOnDirGauge) { + ssGauge.setSection([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.windVariationSector)]); + ssGauge.setSection([]); + } else { + ssGauge.setSection([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.minMaxArea)]); + ssGauge.setArea([]); + } + } else if (config.showRoseOnDirGauge) { + ssGauge.setSection([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.windVariationSector)]); + } else { + ssGauge.setSection([]); + ssGauge.setArea([steelseries.Section(cache.bearingFrom, cache.bearingTo, gaugeGlobals.minMaxArea)]); } - // Check we actually have some data, bad things happen if roseMax=0! - if (roseMax > 0) { - // Find relative value for each point, and create a gauge area for it - for (i = 0; i < rosePoints; i++) { - roseAreas[i] = steelseries.Section( - i * roseSectionAngle - roseSectionAngle / 2, - (i + 1) * roseSectionAngle - roseSectionAngle / 2, - 'rgba(' + gradient('2020D0', 'D04040', data.WindRoseData[i] / roseMax) + ',' + - (data.WindRoseData[i] / roseMax).toFixed(2) + ')' - ); + if (config.showWindMetar) { + if ((range < 60 && range > 0) || range === 0 && cache.bearingFrom === cache.valueAverage) { + ssGauge.VRB += ' STDY'; + } else if (cache.avgKnots < 3) { // Europe uses 3kts, USA 6kts as the threshold + ssGauge.VRB += ' VRB'; + } else { + ssGauge.VRB += ' ' + cache.bearingFrom + 'V' + cache.bearingTo; } } - ssGauge.setArea(roseAreas); - } - - if (ddimgtooltip.showTips) { - // update tooltip - tip = strings.latest_title + ' ' + strings.bearing_info + ': ' + cache.valueLatest + '° (' + getord(+cache.valueLatest) + ')' + - ssGauge.VRB + '
' + strings.tenminavg_web + ' ' + strings.bearing_info + ': ' + cache.valueAverage + '° (' + - getord(+cache.valueAverage) + '), ' + strings.dominant_bearing + ': ' + data.domwinddir; - if (!config.showRoseGauge) { - // Wind run is shown on the wind rose if it is available - tip += '
' + strings.windruntoday + ': ' + data.windrun + ' ' + displayUnits.windrun; + } else { + // Zero wind speed, calm + if (config.showWindMetar) { + ssGauge.VRB = ' - METAR: 00000KT'; + } + ssGauge.setSection([]); + if (!config.showRoseOnDirGauge) { + ssGauge.setArea([]); } - $('#imgtip7_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[7] !== null) { - $('#imgtip7_img').attr('src', config.imgPathURL + config.tipImgs[7] + cacheDefeat); } + } else { + ssGauge.VRB = ''; } - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() + // optional rose data on direction gauge + if (config.showRoseOnDirGauge && data.WindRoseData) { + // Process rose data + rosePoints = data.WindRoseData.length; + roseSectionAngle = 360 / rosePoints; + // Find total for all directions + for (i = 0; i < rosePoints; i++) { + roseMax = Math.max(roseMax, data.WindRoseData[i]); + } + // Check we actually have some data, bad things happen if roseMax=0! + if (roseMax > 0) { + // Find relative value for each point, and create a gauge area for it + for (i = 0; i < rosePoints; i++) { + roseAreas[i] = steelseries.Section( + i * roseSectionAngle - roseSectionAngle / 2, + (i + 1) * roseSectionAngle - roseSectionAngle / 2, + 'rgba(' + gradient('2020D0', 'D04040', data.WindRoseData[i] / roseMax) + ',' + + (data.WindRoseData[i] / roseMax).toFixed(2) + ')' + ); + } + } + ssGauge.setArea(roseAreas); + } + + if (ddimgtooltip.showTips) { + // update tooltip + tip = strings.latest_title + ' ' + strings.bearing_info + ': ' + cache.valueLatest + '° (' + getord(+cache.valueLatest) + ')' + + ssGauge.VRB + '
' + strings.tenminavg_web + ' ' + strings.bearing_info + ': ' + cache.valueAverage + '° (' + + getord(+cache.valueAverage) + '), ' + strings.dominant_bearing + ': ' + data.domwinddir; + if (!config.showRoseGauge) { + // Wind run is shown on the wind rose if it is available + tip += '
' + strings.windruntoday + ': ' + data.windrun + ' ' + displayUnits.windrun; + } + $('#imgtip7_txt').html(tip); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[7] !== null) { + $('#imgtip7_img').attr('src', config.imgPathURL + config.tipImgs[7] + cacheDefeat); + } + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + data: cache, + update: update, + gauge: ssGauge }; - })(), + } // End of init() - // - // Singleton for the Wind Rose Gauge - // - singleRose = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), - var buffers = {}; // Stores references to the various canvas buffers - var cache = {}; // various parameters to store for the life time of gauge - var ctxRoseCanvas; // 2D context for the plotted gauge + // + // Singleton for the Wind Rose Gauge + // + singleRose = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge - cache.firstRun = true; - cache.odoDigits = 5; // Total number of odometer digits including the decimal + var buffers = {}; // Stores references to the various canvas buffers + var cache = {}; // various parameters to store for the life time of gauge + var ctxRoseCanvas; // 2D context for the plotted gauge - function init() { - var div, roseCanvas; - // Get the context of the gauge canvas on the HTML page - if ($('#canvas_rose').length) { - cache.gaugeSize = Math.ceil($('#canvas_rose').width() * config.gaugeScaling); - cache.gaugeSize2 = cache.gaugeSize / 2; - cache.showOdo = config.showRoseGaugeOdo || false; + cache.firstRun = true; + cache.odoDigits = 5; // Total number of odometer digits including the decimal - cache.compassStrings = strings.compass; - cache.titleString = strings.windrose; - cache.gaugeOdoTitle = strings.km; + function init() { + var div, roseCanvas; + // Get the context of the gauge canvas on the HTML page + if ($('#canvas_rose').length) { + cache.gaugeSize = Math.ceil($('#canvas_rose').width() * config.gaugeScaling); + cache.gaugeSize2 = cache.gaugeSize / 2; + cache.showOdo = config.showRoseGaugeOdo || false; - // Create a hidden div to host the Rose plot - div = document.createElement('div'); - div.style.display = 'none'; - document.body.appendChild(div); + cache.compassStrings = strings.compass; + cache.titleString = strings.windrose; + cache.gaugeOdoTitle = strings.km; - // Calcuate the size of the gauge background and so the size of rose plot required - cache.plotSize = Math.floor(cache.gaugeSize * 0.68); - cache.plotSize2 = cache.plotSize / 2; + // Create a hidden div to host the Rose plot + div = document.createElement('div'); + div.style.display = 'none'; + document.body.appendChild(div); - // rose plot canvas buffer - buffers.plot = document.createElement('canvas'); - buffers.plot.width = cache.plotSize; - buffers.plot.height = cache.plotSize; - buffers.plot.id = 'rosePlot'; - buffers.ctxPlot = buffers.plot.getContext('2d'); - div.appendChild(buffers.plot); + // Calcuate the size of the gauge background and so the size of rose plot required + cache.plotSize = Math.floor(cache.gaugeSize * 0.68); + cache.plotSize2 = cache.plotSize / 2; - // Create a steelseries gauge frame - buffers.frame = document.createElement('canvas'); - buffers.frame.width = cache.gaugeSize; - buffers.frame.height = cache.gaugeSize; - buffers.ctxFrame = buffers.frame.getContext('2d'); - steelseries.drawFrame( - buffers.ctxFrame, - gaugeGlobals.frameDesign, - cache.gaugeSize2, - cache.gaugeSize2, - cache.gaugeSize, - cache.gaugeSize - ); + // rose plot canvas buffer + buffers.plot = document.createElement('canvas'); + buffers.plot.width = cache.plotSize; + buffers.plot.height = cache.plotSize; + buffers.plot.id = 'rosePlot'; + buffers.ctxPlot = buffers.plot.getContext('2d'); + div.appendChild(buffers.plot); - // Create a steelseries gauge background - buffers.background = document.createElement('canvas'); - buffers.background.width = cache.gaugeSize; - buffers.background.height = cache.gaugeSize; - buffers.ctxBackground = buffers.background.getContext('2d'); + // Create a steelseries gauge frame + buffers.frame = document.createElement('canvas'); + buffers.frame.width = cache.gaugeSize; + buffers.frame.height = cache.gaugeSize; + buffers.ctxFrame = buffers.frame.getContext('2d'); + steelseries.drawFrame( + buffers.ctxFrame, + gaugeGlobals.frameDesign, + cache.gaugeSize2, + cache.gaugeSize2, + cache.gaugeSize, + cache.gaugeSize + ); + + // Create a steelseries gauge background + buffers.background = document.createElement('canvas'); + buffers.background.width = cache.gaugeSize; + buffers.background.height = cache.gaugeSize; + buffers.ctxBackground = buffers.background.getContext('2d'); + steelseries.drawBackground( + buffers.ctxBackground, + gaugeGlobals.background, + cache.gaugeSize2, + cache.gaugeSize2, + cache.gaugeSize, + cache.gaugeSize + ); + + // Optional - add a background image + /* + if (g_imgSmall !== null) { + var drawSize = g_size * 0.831775; + var x = (g_size - drawSize) / 2; + buffers.ctxBackground.drawImage(g_imgSmall, x, x, cache.gaugeSize, cache.gaugeSize); + } + */ + // Add the compass points + drawCompassPoints(buffers.ctxBackground, cache.gaugeSize); + + // Create a steelseries gauge foreground + buffers.foreground = document.createElement('canvas'); + buffers.foreground.width = cache.gaugeSize; + buffers.foreground.height = cache.gaugeSize; + buffers.ctxForeground = buffers.foreground.getContext('2d'); + steelseries.drawForeground( + buffers.ctxForeground, + gaugeGlobals.foreground, + cache.gaugeSize, + cache.gaugeSize, + false + ); + + roseCanvas = document.getElementById('canvas_rose'); + ctxRoseCanvas = roseCanvas.getContext('2d'); + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_rose').css({ width: cache.gaugeSize + 'px', height: cache.gaugeSize + 'px' }); + } + // resize canvas on main page + roseCanvas.width = cache.gaugeSize; + roseCanvas.height = cache.gaugeSize; + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_rose').css(gaugeShadow(cache.gaugeSize)); + } + + // Render an empty gauge, looks better than just the shadow background and odometer ;) + // Paint the gauge frame + ctxRoseCanvas.drawImage(buffers.frame, 0, 0); + + // Paint the gauge background + ctxRoseCanvas.drawImage(buffers.background, 0, 0); + + // Paint the gauge foreground + ctxRoseCanvas.drawImage(buffers.foreground, 0, 0); + + // Create an odometer + if (cache.showOdo) { + cache.odoHeight = Math.ceil(cache.gaugeSize * 0.08); // Sets the size of the odometer + cache.odoWidth = Math.ceil(Math.floor(cache.odoHeight * 0.68) * cache.odoDigits); // 'Magic' number, do not alter + // Create a new canvas for the oodometer + buffers.Odo = document.createElement('canvas'); + $(buffers.Odo).attr({ + id: 'canvas_odo', + width: cache.odoWidth, + height: cache.odoHeight + }); + // Position it + $(buffers.Odo).attr('class', 'odo'); + // Insert it into the DOM before the Rose gauge + $(buffers.Odo).insertBefore('#canvas_rose'); + // Create the odometer + ssGauge = new steelseries.Odometer('canvas_odo', { + height: cache.odoHeight, + digits: cache.odoDigits - 1, + decimals: 1 + }); + } + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } + + cache.firstRun = false; + + function update() { + var rose, offset; + + if (ctxRoseCanvas && !cache.firstRun) { + // Clear the gauge + ctxRoseCanvas.clearRect(0, 0, cache.gaugeSize, cache.gaugeSize); + + // Clear the existing rose plot + buffers.ctxPlot.clearRect(0, 0, cache.plotSize, cache.plotSize); + + // Create a new rose plot + rose = new RGraph.Rose('rosePlot', data.WindRoseData); + rose.Set('chart.strokestyle', 'black'); + rose.Set('chart.background.axes.color', 'gray'); + rose.Set('chart.colors.alpha', 0.5); + rose.Set('chart.colors', ['Gradient(#408040:red:#7070A0)']); + rose.Set('chart.margin', Math.ceil(40 / data.WindRoseData.length)); + + rose.Set('chart.title', cache.titleString); + rose.Set('chart.title.size', Math.ceil(0.05 * cache.plotSize)); + rose.Set('chart.title.bold', false); + rose.Set('chart.title.color', gaugeGlobals.background.labelColor.getRgbColor()); + rose.Set('chart.gutter.top', 0.2 * cache.plotSize); + rose.Set('chart.gutter.bottom', 0.2 * cache.plotSize); + + rose.Set('chart.tooltips.effect', 'snap'); + rose.Set('chart.labels.axes', ''); + rose.Set('chart.background.circles', true); + rose.Set('chart.background.grid.spokes', 16); + rose.Set('chart.radius', cache.plotSize2); + rose.Draw(); + + // Add title to windrun odometer to the plot + if (cache.showOdo) { + drawOdoTitle(buffers.ctxPlot); + } + + // Paint the gauge frame + ctxRoseCanvas.drawImage(buffers.frame, 0, 0); + + // Paint the gauge background + ctxRoseCanvas.drawImage(buffers.background, 0, 0); + + // Paint the rose plot + offset = Math.floor(cache.gaugeSize2 - cache.plotSize2); + ctxRoseCanvas.drawImage(buffers.plot, offset, offset); + + // Paint the gauge foreground + ctxRoseCanvas.drawImage(buffers.foreground, 0, 0); + + // update the odometer + if (cache.showOdo) { + ssGauge.setValueAnimated(extractDecimal(data.windrun)); + } + + // update tooltip + if (ddimgtooltip.showTips) { + $('#imgtip10_txt').html( + strings.dominant_bearing + ': ' + data.domwinddir + '
' + + strings.windruntoday + ': ' + data.windrun + ' ' + displayUnits.windrun + ); + } + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[10] !== null) { + $('#imgtip10_img').attr('src', config.imgPathURL + config.tipImgs[10] + cacheDefeat); + } + } + + // Helper function to put the compass points on the background + function drawCompassPoints(ctx, size) { + ctx.save(); + // set the font + ctx.font = 0.08 * size + 'px serif'; + ctx.strokeStyle = gaugeGlobals.background.labelColor.getRgbaColor(); + ctx.fillStyle = gaugeGlobals.background.labelColor.getRgbColor(); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + // Draw the compass points + for (var i = 0; i < 4; i++) { + ctx.translate(size / 2, size * 0.125); + ctx.fillText(cache.compassStrings[i * 2], 0, 0, size); + ctx.translate(-size / 2, -size * 0.125); + // Move to center + ctx.translate(size / 2, size / 2); + ctx.rotate(Math.PI / 2); + ctx.translate(-size / 2, -size / 2); + } + ctx.restore(); + } + + function drawOdoTitle(ctx) { + ctx.save(); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = 0.05 * cache.gaugeSize + 'px Arial,Verdana,sans-serif'; + ctx.strokeStyle = gaugeGlobals.background.labelColor.getRgbaColor(); + ctx.fillStyle = gaugeGlobals.background.labelColor.getRgbaColor(); + ctx.fillText(cache.gaugeOdoTitle, cache.plotSize2, cache.plotSize * 0.75, cache.plotSize * 0.5); + ctx.restore(); + } + + function setTitle(newTitle) { + cache.titleString = newTitle; + } + + function setOdoTitle(newTitle) { + cache.gaugeOdoTitle = newTitle; + } + + function setCompassStrings(newArray) { + cache.compassStrings = newArray; + if (!cache.firstRun) { + // Redraw the background steelseries.drawBackground( buffers.ctxBackground, gaugeGlobals.background, @@ -2127,1499 +2334,1293 @@ gauges = (function () { cache.gaugeSize, cache.gaugeSize ); - - // Optional - add a background image - /* - if (g_imgSmall !== null) { - var drawSize = g_size * 0.831775; - var x = (g_size - drawSize) / 2; - buffers.ctxBackground.drawImage(g_imgSmall, x, x, cache.gaugeSize, cache.gaugeSize); - } - */ // Add the compass points drawCompassPoints(buffers.ctxBackground, cache.gaugeSize); - - // Create a steelseries gauge foreground - buffers.foreground = document.createElement('canvas'); - buffers.foreground.width = cache.gaugeSize; - buffers.foreground.height = cache.gaugeSize; - buffers.ctxForeground = buffers.foreground.getContext('2d'); - steelseries.drawForeground( - buffers.ctxForeground, - gaugeGlobals.foreground, - cache.gaugeSize, - cache.gaugeSize, - false - ); - - roseCanvas = document.getElementById('canvas_rose'); - ctxRoseCanvas = roseCanvas.getContext('2d'); - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_rose').css({width: cache.gaugeSize + 'px', height: cache.gaugeSize + 'px'}); - } - // resize canvas on main page - roseCanvas.width = cache.gaugeSize; - roseCanvas.height = cache.gaugeSize; - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_rose').css(gaugeShadow(cache.gaugeSize)); - } - - // Render an empty gauge, looks better than just the shadow background and odometer ;) - // Paint the gauge frame - ctxRoseCanvas.drawImage(buffers.frame, 0, 0); - - // Paint the gauge background - ctxRoseCanvas.drawImage(buffers.background, 0, 0); - - // Paint the gauge foreground - ctxRoseCanvas.drawImage(buffers.foreground, 0, 0); - - // Create an odometer - if (cache.showOdo) { - cache.odoHeight = Math.ceil(cache.gaugeSize * 0.08); // Sets the size of the odometer - cache.odoWidth = Math.ceil(Math.floor(cache.odoHeight * 0.68) * cache.odoDigits); // 'Magic' number, do not alter - // Create a new canvas for the oodometer - buffers.Odo = document.createElement('canvas'); - $(buffers.Odo).attr({ - id : 'canvas_odo', - width : cache.odoWidth, - height: cache.odoHeight - }); - // Position it - $(buffers.Odo).attr('class', 'odo'); - // Insert it into the DOM before the Rose gauge - $(buffers.Odo).insertBefore('#canvas_rose'); - // Create the odometer - ssGauge = new steelseries.Odometer('canvas_odo', { - height : cache.odoHeight, - digits : cache.odoDigits - 1, - decimals: 1 - }); - } - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; } - - cache.firstRun = false; - - function update() { - var rose, offset; - - if (ctxRoseCanvas && !cache.firstRun) { - // Clear the gauge - ctxRoseCanvas.clearRect(0, 0, cache.gaugeSize, cache.gaugeSize); - - // Clear the existing rose plot - buffers.ctxPlot.clearRect(0, 0, cache.plotSize, cache.plotSize); - - // Create a new rose plot - rose = new RGraph.Rose('rosePlot', data.WindRoseData); - rose.Set('chart.strokestyle', 'black'); - rose.Set('chart.background.axes.color', 'gray'); - rose.Set('chart.colors.alpha', 0.5); - rose.Set('chart.colors', ['Gradient(#408040:red:#7070A0)']); - rose.Set('chart.margin', Math.ceil(40 / data.WindRoseData.length)); - - rose.Set('chart.title', cache.titleString); - rose.Set('chart.title.size', Math.ceil(0.05 * cache.plotSize)); - rose.Set('chart.title.bold', false); - rose.Set('chart.title.color', gaugeGlobals.background.labelColor.getRgbColor()); - rose.Set('chart.gutter.top', 0.2 * cache.plotSize); - rose.Set('chart.gutter.bottom', 0.2 * cache.plotSize); - - rose.Set('chart.tooltips.effect', 'snap'); - rose.Set('chart.labels.axes', ''); - rose.Set('chart.background.circles', true); - rose.Set('chart.background.grid.spokes', 16); - rose.Set('chart.radius', cache.plotSize2); - rose.Draw(); - - // Add title to windrun odometer to the plot - if (cache.showOdo) { - drawOdoTitle(buffers.ctxPlot); - } - - // Paint the gauge frame - ctxRoseCanvas.drawImage(buffers.frame, 0, 0); - - // Paint the gauge background - ctxRoseCanvas.drawImage(buffers.background, 0, 0); - - // Paint the rose plot - offset = Math.floor(cache.gaugeSize2 - cache.plotSize2); - ctxRoseCanvas.drawImage(buffers.plot, offset, offset); - - // Paint the gauge foreground - ctxRoseCanvas.drawImage(buffers.foreground, 0, 0); - - // update the odometer - if (cache.showOdo) { - ssGauge.setValueAnimated(extractDecimal(data.windrun)); - } - - // update tooltip - if (ddimgtooltip.showTips) { - $('#imgtip10_txt').html( - strings.dominant_bearing + ': ' + data.domwinddir + '
' + - strings.windruntoday + ': ' + data.windrun + ' ' + displayUnits.windrun - ); - } - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[10] !== null) { - $('#imgtip10_img').attr('src', config.imgPathURL + config.tipImgs[10] + cacheDefeat); - } - } - - // Helper function to put the compass points on the background - function drawCompassPoints(ctx, size) { - ctx.save(); - // set the font - ctx.font = 0.08 * size + 'px serif'; - ctx.strokeStyle = gaugeGlobals.background.labelColor.getRgbaColor(); - ctx.fillStyle = gaugeGlobals.background.labelColor.getRgbColor(); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - - // Draw the compass points - for (var i = 0; i < 4; i++) { - ctx.translate(size / 2, size * 0.125); - ctx.fillText(cache.compassStrings[i * 2], 0, 0, size); - ctx.translate(-size / 2, -size * 0.125); - // Move to center - ctx.translate(size / 2, size / 2); - ctx.rotate(Math.PI / 2); - ctx.translate(-size / 2, -size / 2); - } - ctx.restore(); - } - - function drawOdoTitle(ctx) { - ctx.save(); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.font = 0.05 * cache.gaugeSize + 'px Arial,Verdana,sans-serif'; - ctx.strokeStyle = gaugeGlobals.background.labelColor.getRgbaColor(); - ctx.fillStyle = gaugeGlobals.background.labelColor.getRgbaColor(); - ctx.fillText(cache.gaugeOdoTitle, cache.plotSize2, cache.plotSize * 0.75, cache.plotSize * 0.5); - ctx.restore(); - } - - function setTitle(newTitle) { - cache.titleString = newTitle; - } - - function setOdoTitle(newTitle) { - cache.gaugeOdoTitle = newTitle; - } - - function setCompassStrings(newArray) { - cache.compassStrings = newArray; - if (!cache.firstRun) { - // Redraw the background - steelseries.drawBackground( - buffers.ctxBackground, - gaugeGlobals.background, - cache.gaugeSize2, - cache.gaugeSize2, - cache.gaugeSize, - cache.gaugeSize - ); - // Add the compass points - drawCompassPoints(buffers.ctxBackground, cache.gaugeSize); - } - } - - return { - update : update, - gauge : ssGauge, - drawCompassPoints: drawCompassPoints, - setTitle : setTitle, - setCompassStrings: setCompassStrings, - setOdoTitle : setOdoTitle - }; - } // End of init() + } return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } + update: update, + gauge: ssGauge, + drawCompassPoints: drawCompassPoints, + setTitle: setTitle, + setCompassStrings: setCompassStrings, + setOdoTitle: setOdoTitle }; - })(), + } // End of init() - // - // Singleton for the UV-Index Gauge - // - singleUV = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters - - function init() { - var params = $.extend(true, {}, commonParams); - - // define UV start values - cache.value = 0.0001; - cache.sections = [ - steelseries.Section(0, 2.9, '#289500'), - steelseries.Section(2.9, 5.8, '#f7e400'), - steelseries.Section(5.8, 7.8, '#f85900'), - steelseries.Section(7.8, 10.9, '#d8001d'), - steelseries.Section(10.9, 20, '#6b49c8') - ]; - // Define value gradient for UV - cache.gradient = new steelseries.gradientWrapper(0, 16, - [0, 0.1, 0.19, 0.31, 0.45, 0.625, 1], - [ - new steelseries.rgbaColor(0, 200, 0, 1), - new steelseries.rgbaColor(0, 200, 0, 1), - new steelseries.rgbaColor(255, 255, 0, 1), - new steelseries.rgbaColor(248, 89, 0, 1), - new steelseries.rgbaColor(255, 0, 0, 1), - new steelseries.rgbaColor(255, 0, 144, 1), - new steelseries.rgbaColor(153, 140, 255, 1) - ] - ); - cache.useSections = false; - cache.useValueGradient = true; - - // create UV bargraph gauge - if ($('#canvas_uv').length) { - params.size = Math.ceil($('#canvas_uv').width() * config.gaugeScaling); - params.gaugeType = steelseries.GaugeType.TYPE3; - params.maxValue = gaugeGlobals.uvScaleDefMax; - params.titleString = strings.uv_title; - params.niceScale = false; - params.section = cache.sections; - params.useSectionColors = cache.useSections; - params.valueGradient = cache.gradient; - params.useValueGradient = cache.useValueGradient; - params.lcdDecimals = gaugeGlobals.uvLcdDecimals; - - ssGauge = new steelseries.RadialBargraph('canvas_uv', params); - ssGauge.setValue(cache.value); - - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_uv').css({width: params.size + 'px', height: params.size + 'px'}); - } - - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_uv').css(gaugeShadow(params.size)); - } - - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); } - - function update() { - var tip, indx; - - cache.value = extractDecimal(data.UV); - - if (+cache.value === 0) { - indx = 0; - } else if (cache.value < 2.5) { - indx = 1; - } else if (cache.value < 5.5) { - indx = 2; - } else if (cache.value < 7.5) { - indx = 3; - } else if (cache.value < 10.5) { - indx = 4; - } else { - indx = 5; - } - - cache.maxValue = Math.max(nextHighest(cache.value, 2), gaugeGlobals.uvScaleDefMax); - if (cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setValue(0); - ssGauge.setMaxValue(cache.maxValue); - } - - cache.risk = strings.uv_levels[indx]; - cache.headLine = strings.uv_headlines[indx]; - cache.detail = strings.uv_details[indx]; - ssGauge.setUnitString(cache.risk); - ssGauge.setValueAnimated(cache.value); - - if (ddimgtooltip.showTips) { - // update tooltip - tip = '' + strings.uv_title + ': ' + cache.value + ' - ' + strings.solar_maxToday + ': ' + data.UVTH + '
'; - tip += '' + cache.headLine + '
'; - tip += cache.detail; - $('#imgtip8_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[8] !== null) { - $('#imgtip8_img').attr('src', config.imgPathURL + config.tipImgs[8] + cacheDefeat); - } - } - - return { - update: update, - gauge : ssGauge - }; - } // End of init() - - return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } - }; - })(), - - // - // Singleton for the Solar Irradiation Gauge - // - singleSolar = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters - - function init() { - var params = $.extend(true, {}, commonParams); - - // define Solar start values - cache.value = 0.0001; - cache.sections = [ - steelseries.Section(0, 600, 'rgba(40,149,0,0.3)'), - steelseries.Section(600, 800, 'rgba(248,89,0,0.3)'), - steelseries.Section(800, 1000, 'rgba(216,0,29,0.3)'), - steelseries.Section(1000, 1800, 'rgba(107,73,200,0.3)') - ]; - - // create Solar gauge - if ($('#canvas_solar').length) { - params.size = Math.ceil($('#canvas_solar').width() * config.gaugeScaling); - params.section = cache.sections; - params.maxValue = gaugeGlobals.solarGaugeScaleMax; - params.titleString = strings.solar_title; - params.unitString = 'W/m\u00B2'; - params.niceScale = false; - params.thresholdVisible = false; - params.lcdDecimals = 0; - - if (config.showSunshineLed) { - params.userLedVisible = true; - params.userLedColor = steelseries.LedColor.YELLOW_LED; - } - - ssGauge = new steelseries.Radial('canvas_solar', params); - ssGauge.setValue(cache.value); - - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_solar').css({width: params.size + 'px', height: params.size + 'px'}); - } - - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_solar').css(gaugeShadow(params.size)); - } - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; - } - - function update() { - var tip, percent; - - cache.value = +extractInteger(data.SolarRad); - cache.maxToday = extractInteger(data.SolarTM); - cache.currMaxValue = +extractInteger(data.CurrentSolarMax); - percent = (+cache.currMaxValue === 0 ? '--' : Math.round(+cache.value / +cache.currMaxValue * 100)); - - // Need to rescale the gauge? - cache.maxValue = Math.max(cache.value, cache.currMaxValue, cache.maxToday, gaugeGlobals.solarGaugeScaleMax); - cache.maxValue = nextHighest(cache.maxValue, 100); - if (cache.maxValue !== ssGauge.getMaxValue()) { - ssGauge.setValue(0); - ssGauge.setMaxValue(cache.maxValue); - } - - // Set a section (15% of maxScale wide) to show current theoretical max value - if (data.CurrentSolarMax !== 'N/A') { - ssGauge.setArea([ - // Sunshine threshold - steelseries.Section( - Math.max(cache.currMaxValue * gaugeGlobals.sunshineThresholdPct / 100, gaugeGlobals.sunshineThreshold), - cache.currMaxValue, - 'rgba(255,255,50,0.4)' - ), - // Over max threshold - steelseries.Section( - cache.currMaxValue, - Math.min(cache.currMaxValue + cache.maxValue * 0.15, cache.maxValue), - 'rgba(220,0,0,0.5)' - ) - ]); - } - - // Set the values - ssGauge.setMaxMeasuredValue(cache.maxToday); - ssGauge.setValueAnimated(cache.value); - - if (config.showSunshineLed) { - ssGauge.setUserLedOnOff( - percent !== '--' && - percent >= gaugeGlobals.sunshineThresholdPct && - +cache.value >= gaugeGlobals.sunshineThreshold - ); - } - - if (ddimgtooltip.showTips) { - // update tooltip - tip = '' + strings.solar_title + ': ' + cache.value + ' W/m² - ' + - '' + percent + '% ' + strings.solar_ofMax + '
' + - strings.solar_currentMax + ': ' + cache.currMaxValue + ' W/m²'; - if (typeof data.SolarTM !== 'undefined') { - tip += '
' + strings.solar_maxToday + ': ' + cache.maxToday + ' W/m²'; - } - $('#imgtip9_txt').html(tip); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[9] !== null) { - $('#imgtip9_img').attr('src', config.imgPathURL + config.tipImgs[9] + cacheDefeat); - } - } - - return { - update: update, - gauge : ssGauge - }; - } // End of init() - - return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } - }; - })(), - - // - // Singleton for the Cloudbase Gauge - // - singleCloudBase = (function () { - var instance; // Stores a reference to the Singleton - var ssGauge; // Stores a reference to the SS Gauge - var cache = {}; // Stores various config values and parameters - - function init() { - var params = $.extend(true, {}, commonParams); - - cache.sections = createCloudBaseSections(true); - cache.value = 0.0001; - cache.maxValue = gaugeGlobals.cloudScaleDefMaxm; - - // create Cloud base radial gauge - if ($('#canvas_cloud').length) { - params.size = Math.ceil($('#canvas_cloud').width() * config.gaugeScaling); - params.section = cache.sections; - params.maxValue = cache.maxValue; - params.titleString = strings.cloudbase_title; - params.unitString = strings.metres; - params.thresholdVisible = false; - params.lcdDecimals = 0; - - ssGauge = new steelseries.Radial('canvas_cloud', params); - ssGauge.setValue(cache.value); - - // over-ride CSS applied size? - if (config.gaugeScaling !== 1) { - $('#canvas_cloud').css({width: params.size + 'px', height: params.size + 'px'}); - } - - // add a shadow to the gauge - if (config.showGaugeShadow) { - $('#canvas_cloud').css(gaugeShadow(params.size)); - } - // subscribe to data updates - $.subscribe('gauges.dataUpdated', update); - $.subscribe('gauges.graphUpdate', updateGraph); - } else { - // cannot draw gauge, return null - return null; - } - - function update() { - cache.value = extractInteger(data.cloudbasevalue); - - if (data.cloudbaseunit === 'm') { - // adjust metre gauge in jumps of 1000 metres, don't downscale during the session - cache.maxValue = Math.max(nextHighest(cache.value, 1000), gaugeGlobals.cloudScaleDefMaxm, cache.maxValue); - if (cache.value <= 1000 && config.roundCloudbaseVal) { - // and round the value to the nearest 10 m - cache.value = Math.round(cache.value / 10) * 10; - } else if (config.roundCloudbaseVal) { - // and round the value to the nearest 50 m - cache.value = Math.round(cache.value / 50) * 50; - } - } else { - // adjust feet gauge in jumps of 2000 ft, don't downscale during the session - cache.maxValue = Math.max(nextHighest(cache.value, 2000), gaugeGlobals.cloudScaleDefMaxft, cache.maxValue); - if (cache.value <= 2000 && config.roundCloudbaseVal) { - // and round the value to the nearest 50 ft - cache.value = Math.round(cache.value / 50) * 50; - } else if (config.roundCloudbaseVal) { - // and round the value to the nearest 100 ft - cache.value = Math.round(cache.value / 100) * 100; - } - } - - if (cache.maxValue !== ssGauge.getMaxValue()) { - if (ssGauge.getMaxValue() > cache.maxValue) { - // Gauge currently showing more than our max (nice scale effct), - // so reset our max to match - cache.maxValue = ssGauge.getMaxValue(); - } else { - // Gauge scale is too low, increase it. - // First set the pointer back to zero so we get a nice animation - ssGauge.setValue(0); - // and redraw the gauge with teh new scale - ssGauge.setMaxValue(cache.maxValue); - } - } - ssGauge.setValueAnimated(cache.value); - - if (config.showPopupData) { - // static tooltip on cloud gauge - $('#imgtip11_txt').html('' + strings.cloudbase_popup_title + '
' + strings.cloudbase_popup_text); - } - } // End of update() - - function updateGraph(evnt, cacheDefeat) { - if (config.tipImgs[11] !== null) { - $('#imgtip11_img').attr('src', config.imgPathURL + config.tipImgs[11] + cacheDefeat); - } - } - - return { - data : cache, - update: update, - gauge : ssGauge - }; - } // End of init() - - return { - // Get the Singleton instance if one exists - // or create one if it doesn't - getInstance: function () { - if (!instance) { - instance = init(); - } - return instance; - } - }; - })(), - - // - // getRealtime() fetches the realtimegauges JSON data from the server - // - getRealtime = function () { - var url = config.realTimeURL; - if ($.active > 0 && undefined != jqXHR) { - // kill any outstanding requests - jqXHR.abort(); + return instance; } - if (config.longPoll) { - url += '?timestamp=' + timestamp; - } - jqXHR = $.ajax({ - url : url, - cache : (config.longPoll), - dataType: 'json', - timeout : config.longPoll ? (Math.min(config.realtimeInterval, 20) + 21) * 1000 : 21000 // 21 second time-out by default - }).done(function (data) { - checkRtResp(data); - }).fail(function (xhr, status, err) { - checkRtError(xhr, status, err); - }); - }, + }; + })(), - // - // checkRtResp() called by the Ajax fetch once data has been downloaded - // - checkRtResp = function (response) { - var delay; - statusTimer.reset(config.longPoll ? 1 : config.realtimeInterval); - if (config.longPoll && response.status !== 'OK') { - checkRtError(null, 'PHP Error', response.status); - } else { - if (processData(response)) { - delay = ajaxDelay; - } else { - delay = 5; - } - if (delay > 0) { - downloadTimer = setTimeout(getRealtime, delay * 1000); - } else { - getRealtime(); - } - } - }, + // + // Singleton for the UV-Index Gauge + // + singleUV = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters - // - // checkRtError() called by the Ajax fetch if an error occurs during the fetching realtimegauges.txt - // - checkRtError = function (xhr, status, error) { - if (xhr == null || xhr.statusText !== 'abort') { - // Clear any existing download timer - clearTimeout(downloadTimer); - // Set the status LED to off - ledIndicator.setLedOnOff(false); - ledIndicator.setTitle(strings.led_title_unknown); - statusScroller.setText(status + ': ' + error); - // wait 5 seconds, then try again... - downloadTimer = setTimeout(getRealtime, 5000); - } - }, + function init() { + var params = $.extend(true, {}, commonParams); - // - // processData() massages the data returned in realtimegauges.txt, and posts a gauges.dataUpdated event to update the page - // - processData = function (dataObj) { - var str, dt, tm, today, now, then, tmp, elapsedMins, retVal; - // copy the realtime fields into the global 'data' object - if (config.longPoll) { - timestamp = dataObj.timestamp; - data = dataObj.data; - } else { - // normal polling - data = dataObj; - } - - // and check we have the expected version number - if (typeof data.ver !== 'undefined' && data.ver >= realtimeVer) { - // manpulate the last rain time into something more friendly - try { - str = data.LastRainTipISO.split(' '); - dt = str[0].replace(/\//g, '-').split('-'); // WD uses dd/mm/yyyy, we use a '-' - tm = str[1].split(':'); - today = new Date(); - today.setHours(0, 0, 0, 0); - if (typeof data.dateFormat === 'undefined') { - data.dateFormat = 'y/m/d'; - } else { - // frig for WD bug which leaves a trailing % character from the tag - data.dateFormat = data.dateFormat.replace('%', ''); - } - if (data.dateFormat === 'y/m/d') { - // ISO/Cumulus format - then = new Date(dt[0], dt[1] - 1, dt[2], tm[0], tm[1], 0, 0); - } else if (data.dateFormat === 'd/m/y') { - then = new Date(dt[2], dt[1] - 1, dt[0], tm[0], tm[1], 0, 0); - } else { // m/d/y - then = new Date(dt[2], dt[0] - 1, dt[1], tm[0], tm[1], 0, 0); - } - if (then.getTime() >= today.getTime()) { - data.LastRained = strings.LastRainedT_info + ' ' + str[1]; - } else if (then.getTime() + 86400000 >= today.getTime()) { - data.LastRained = strings.LastRainedY_info + ' ' + str[1]; - } else { - data.LastRained = then.getDate().toString() + ' ' + strings.months[then.getMonth()] + ' ' + strings.at + ' ' + str[1]; - } - } catch (e) { - data.LastRained = data.LastRainTipISO; - } - if (data.tempunit.length > 1) { - // clean up temperature units - remove html encoded degree symbols - data.tempunit = data.tempunit.replace(/&\S*;/, '°'); // old Cumulus versions uses °, WeatherCat uses ° - } else { - // using new realtimegaugesT.txt with Cumulus > 1.9.2 - data.tempunit = '°' + data.tempunit; - } - - // Check for station off-line - now = Date.now(); - tmp = data.timeUTC.split(','); - sampleDate = Date.UTC(tmp[0], tmp[1] - 1, tmp[2], tmp[3], tmp[4], tmp[5]); - if (now - sampleDate > config.stationTimeout * 60 * 1000) { - elapsedMins = Math.floor((now - sampleDate) / (1000 * 60)); - // the realtimegauges.txt file isn't being updated - ledIndicator.setLedColor(steelseries.LedColor.RED_LED); - ledIndicator.setTitle(strings.led_title_offline); - ledIndicator.blink(true); - if (elapsedMins < 120) { - // up to 2 hours ago - tm = elapsedMins.toString() + ' ' + strings.StatusMinsAgo; - } else if (elapsedMins < 2 * 24 * 60) { - // up to 48 hours ago - tm = Math.floor(elapsedMins / 60).toString() + ' ' + strings.StatusHoursAgo; - } else { - // days ago! - tm = Math.floor(elapsedMins / (60 * 24)).toString() + ' ' + strings.StatusDaysAgo; - } - data.forecast = strings.led_title_offline + ' ' + strings.StatusLastUpdate + ' ' + tm; - } else if (+data.SensorContactLost === 1) { - // Fine Offset sensor status - ledIndicator.setLedColor(steelseries.LedColor.RED_LED); - ledIndicator.setTitle(strings.led_title_lost); - ledIndicator.blink(true); - data.forecast = strings.led_title_lost; - } else { - ledIndicator.setLedColor(steelseries.LedColor.GREEN_LED); - ledIndicator.setTitle(strings.led_title_ok + '. ' + strings.StatusLastUpdate + ': ' + data.date); - ledIndicator.blink(false); - ledIndicator.setLedOnOff(true); - } - - // de-encode the forecast string if required (Cumulus support for extended characters) - data.forecast = $('
').html(data.forecast).text(); - data.forecast = data.forecast.trim(); - - data.pressunit = data.pressunit.trim(); // WView sends ' in', ' mb', or ' hPa' - if (data.pressunit === 'in') { // Cumulus and WView send 'in' - data.pressunit = 'inHg'; - } - - data.windunit = data.windunit.trim(); // WView sends ' kmh' etc - data.windunit = data.windunit.toLowerCase(); // WeatherCat sends "MPH" - if (data.windunit === 'knots') { // WeatherCat/weewx send "Knots", we use "kts" - data.windunit = 'kts'; - } - - if (data.windunit === 'kmh' || data.windunit === 'kph') { // WD wind unit omits '/', weewx sends 'kph' - data.windunit = 'km/h'; - } - - data.rainunit = data.rainunit.trim(); // WView sends ' mm' etc - - // take a look at the cloud base data... - // change WeatherCat units from Metres/Feet to m/ft - try { - if (data.cloudbaseunit.toLowerCase() === 'metres') { - data.cloudbaseunit = 'm'; - } else if (data.cloudbaseunit.toLowerCase() === 'feet') { - data.cloudbaseunit = 'ft'; - } - } catch (e) { - data.cloudbaseunit = ''; - } - if (config.showCloudGauge && ( - (config.weatherProgram === 4 || config.weatherProgram === 5) || - data.cloudbasevalue === '')) { - // WeatherCat and VWS (and WView?) do not provide a cloud base value, so we have to calculate it... - // assume if the station uses an imperial wind speed they want cloud base in feet, otherwise metres - data.cloudbaseunit = (data.windunit === 'mph' || data.windunit === 'kts') ? 'ft' : 'm'; - data.cloudbasevalue = calcCloudbase(data.temp, data.tempunit, data.dew, data.cloudbaseunit); - } - - // Temperature data conversion for display required? - if (data.tempunit[1] !== displayUnits.temp && userUnitsSet) { - // temp needs converting - if (data.tempunit[1] === 'C') { - convTempData(c2f); - } else { - convTempData(f2c); - } - } else if (firstRun) { - displayUnits.temp = data.tempunit[1]; - setRadioCheck('rad_unitsTemp', displayUnits.temp); - } - - // Rain data conversion for display required? - if (data.rainunit !== displayUnits.rain && userUnitsSet) { - // rain needs converting - convRainData(displayUnits.rain === 'mm' ? in2mm : mm2in); - } else if (firstRun) { - displayUnits.rain = data.rainunit; - setRadioCheck('rad_unitsRain', displayUnits.rain); - } - - // Wind data conversion for display required? - if (data.windunit !== displayUnits.wind && userUnitsSet) { - // wind needs converting - convWindData(data.windunit, displayUnits.wind); - } else if (firstRun) { - displayUnits.wind = data.windunit; - displayUnits.windrun = getWindrunUnits(data.windunit); - setRadioCheck('rad_unitsWind', displayUnits.wind); - } - - // Pressure data conversion for display required? - if (data.pressunit !== displayUnits.press && userUnitsSet) { - convBaroData(data.pressunit, displayUnits.press); - } else if (firstRun) { - displayUnits.press = data.pressunit; - setRadioCheck('rad_unitsPress', displayUnits.press); - } - - // Cloud height data conversion for display required? - if (data.cloudbaseunit !== displayUnits.cloud && userUnitsSet) { - // Cloud height needs converting - convCloudBaseData(displayUnits.cloud === 'm' ? ft2m : m2ft); - } else if (firstRun) { - displayUnits.cloud = data.cloudbaseunit; - setRadioCheck('rad_unitsCloud', displayUnits.cloud); - } - - statusScroller.setText(data.forecast); - - // first time only, setup units etc - if (firstRun) { - doFirst(); - } - - // publish the update, use the shared data object rather than transferring it - $.publish('gauges.dataUpdated', {}); - - retVal = true; - } else { - // set an error message - if (data.ver < realtimeVer) { - statusTimer.setValue(0); - statusScroller.setText('Your ' + config.realTimeURL.substr(config.realTimeURL.lastIndexOf('/') + 1) + ' file template needs updating!'); - return false; - } else { - // oh-oh! The number of data fields isn't what we expected - statusScroller.setText(strings.realtimeCorrupt); - } - ledIndicator.setLedOnOff(false); - ledIndicator.setTitle(strings.led_title_unknown); - - retVal = false; - } - return retVal; - }, - - // - // pagetimeout() called once every config.pageUpdateLimit minutes to stop updates and prevent page 'sitters' - // - pageTimeout = function () { - statusScroller.setText(strings.StatusPageLimit); - ledIndicator.setLedColor(steelseries.LedColor.RED_LED); - ledIndicator.setTitle(strings.StatusPageLimit); - ledIndicator.blink(true); - ledIndicator.setTitle(strings.StatusTimeout); - - // stop any pending download - clearTimeout(downloadTimer); - - // stop any long polling in progress - if ($.active > 0) { - jqXHR.abort(); - } - - // stop the clock - clearInterval(tickTockInterval); - - // clear the timer display - statusTimer.setValue(0); - - // set an onclick event on the LED to restart everything - $('#canvas_led').click( - function click() { - // disable the onClick event again - $('#canvas_led').unbind('click'); - // reset the timer count to 1 - statusTimer.reset(1); - // restart the timer to update the status time - tickTockInterval = setInterval( - function tick() { - $.publish('gauges.clockTick', null); - }, - 1000 - ); - - // restart the page timeout timer, so we hit this code again - setTimeout(pageTimeout, config.pageUpdateLimit * 60 * 1000); - - // refresh the page data - getRealtime(); - } - ); - }, - - // - // doFirst() called by doUpdate() the first time the page is updated to set-up various things that are - // only known when the realtimegauges.txt data is available - // - doFirst = function () { - var cacheDefeat = '?' + (new Date()).getTime().toString(); - - if (data.tempunit[1] === 'F') { - displayUnits.temp = 'F'; - setRadioCheck('rad_unitsTemp', 'F'); - setTempUnits(false); - } - - if (data.pressunit !== 'hPa') { - displayUnits.press = data.pressunit; - setRadioCheck('rad_unitsPress', data.pressunit); - setBaroUnits(data.pressunit); - } - - if (data.windunit !== 'km/h') { - displayUnits.wind = data.windunit; - setRadioCheck('rad_unitsWind', data.windunit); - setWindUnits(data.windunit); - } - - if (data.rainunit !== 'mm') { - displayUnits.rain = data.rainunit; - setRadioCheck('rad_unitsRain', data.rainunit); - setRainUnits(false); - } - - if (config.showSolarGauge && typeof data.SolarTM !== 'undefined' && gaugeSolar) { - gaugeSolar.gauge.setMaxMeasuredValueVisible(true); - } - - if (config.showCloudGauge && data.cloudbaseunit !== 'm') { - displayUnits.cloud = data.cloudbaseunit; - setRadioCheck('rad_unitsCloud', data.cloudbaseunit); - setCloudBaseUnits(false); - } - - // set the script version on the page - $('#scriptVer').html(config.scriptVer); - // set the version information from the station - $('#programVersion').html(data.version); - $('#programBuild').html(data.build); - $('#programName').html(programLink[config.weatherProgram]); - - if (config.showPopupData) { - // now initialise the pop-up script and download the trend images - // - has to be done here as doFirst may remove elements from the page - // - and we delay the download of the images speeding up page display - ddimgtooltip.init('[id^="tip_"]'); - // Are we running on a phone device (or really low res screen)? - if ($(window).width() < 480) { - $('.ddimgtooltip').filter(':hidden').width('200px'); - } - } - - if (config.showPopupData && config.showPopupGraphs) { - // now download the trend images - // - has to be done here as doFirst may remove elements from the page - // - and we delay the download of the images speeding up page display - // - $('#imgtip0_img').attr('src', config.imgPathURL + config.tipImgs[0][0] + cacheDefeat); - if (gaugeDew) { - $('#imgtip1_img').attr('src', config.imgPathURL + config.tipImgs[1][gaugeDew.data.popupImg] + cacheDefeat); - } - $('#imgtip2_img').attr('src', config.imgPathURL + config.tipImgs[2] + cacheDefeat); - $('#imgtip3_img').attr('src', config.imgPathURL + config.tipImgs[3] + cacheDefeat); - $('#imgtip4_img').attr('src', config.imgPathURL + config.tipImgs[4][0] + cacheDefeat); - $('#imgtip5_img').attr('src', config.imgPathURL + config.tipImgs[5] + cacheDefeat); - $('#imgtip6_img').attr('src', config.imgPathURL + config.tipImgs[6] + cacheDefeat); - $('#imgtip7_img').attr('src', config.imgPathURL + config.tipImgs[7] + cacheDefeat); - $('#imgtip8_img').attr('src', config.imgPathURL + config.tipImgs[8] + cacheDefeat); - $('#imgtip9_img').attr('src', config.imgPathURL + config.tipImgs[9] + cacheDefeat); - $('#imgtip10_img').attr('src', config.imgPathURL + config.tipImgs[10] + cacheDefeat); - $('#imgtip11_img').attr('src', config.imgPathURL + config.tipImgs[11] + cacheDefeat); - // start a timer for popup graphic updates - setInterval( - function timeout() { - $.publish('gauges.graphUpdate', '?' + (new Date()).getTime().toString()); - }, - config.graphUpdateTime * 60 * 1000 - ); - } - - firstRun = false; - }, - - // - // createTempSections() creates an array of gauge sections appropriate for Celsius or Fahrenheit scales - // - createTempSections = function (celsius) { - var section; - if (celsius) { - section = [ - steelseries.Section(-100, -35, 'rgba(195, 92, 211, 0.4)'), - steelseries.Section(-35, -30, 'rgba(139, 74, 197, 0.4)'), - steelseries.Section(-30, -25, 'rgba(98, 65, 188, 0.4)'), - steelseries.Section(-25, -20, 'rgba(62, 66, 185, 0.4)'), - steelseries.Section(-20, -15, 'rgba(42, 84, 194, 0.4)'), - steelseries.Section(-15, -10, 'rgba(25, 112, 210, 0.4)'), - steelseries.Section(-10, -5, 'rgba(9, 150, 224, 0.4)'), - steelseries.Section(-5, 0, 'rgba(2, 170, 209, 0.4)'), - steelseries.Section(0, 5, 'rgba(0, 162, 145, 0.4)'), - steelseries.Section(5, 10, 'rgba(0, 158, 122, 0.4)'), - steelseries.Section(10, 15, 'rgba(54, 177, 56, 0.4)'), - steelseries.Section(15, 20, 'rgba(111, 202, 56, 0.4)'), - steelseries.Section(20, 25, 'rgba(248, 233, 45, 0.4)'), - steelseries.Section(25, 30, 'rgba(253, 142, 42, 0.4)'), - steelseries.Section(30, 40, 'rgba(236, 45, 45, 0.4)'), - steelseries.Section(40, 100, 'rgba(245, 109, 205, 0.4)') - ]; - } else { - section = [ - steelseries.Section(-200, -30, 'rgba(195, 92, 211, 0.4)'), - steelseries.Section(-30, -25, 'rgba(139, 74, 197, 0.4)'), - steelseries.Section(-25, -15, 'rgba(98, 65, 188, 0.4)'), - steelseries.Section(-15, -5, 'rgba(62, 66, 185, 0.4)'), - steelseries.Section(-5, 5, 'rgba(42, 84, 194, 0.4)'), - steelseries.Section(5, 15, 'rgba(25, 112, 210, 0.4)'), - steelseries.Section(15, 25, 'rgba(9, 150, 224, 0.4)'), - steelseries.Section(25, 32, 'rgba(2, 170, 209, 0.4)'), - steelseries.Section(32, 40, 'rgba(0, 162, 145, 0.4)'), - steelseries.Section(40, 50, 'rgba(0, 158, 122, 0.4)'), - steelseries.Section(50, 60, 'rgba(54, 177, 56, 0.4)'), - steelseries.Section(60, 70, 'rgba(111, 202, 56, 0.4)'), - steelseries.Section(70, 80, 'rgba(248, 233, 45, 0.4)'), - steelseries.Section(80, 90, 'rgba(253, 142, 42, 0.4)'), - steelseries.Section(90, 110, 'rgba(236, 45, 45, 0.4)'), - steelseries.Section(110, 200, 'rgba(245, 109, 205, 0.4)') - ]; - } - return section; - }, - - // - // createRainSections() returns an array of section highlights for the Rain Rate gauge - // - /* - Assumes 'standard' descriptive limits from UK met office: - < 0.25 mm/hr - Very light rain - 0.25mm/hr to 1.0mm/hr - Light rain - 1.0 mm/hr to 4.0 mm/hr - Moderate rain - 4.0 mm/hr to 16.0 mm/hr - Heavy rain - 16.0 mm/hr to 50 mm/hr - Very heavy rain - > 50.0 mm/hour - Extreme rain - - Roughly translated to the corresponding Inch rates - < 0.001 - 0.001 to 0.05 - 0.05 to 0.20 - 0.20 to 0.60 - 0.60 to 2.0 - > 2.0 - */ - createRainRateSections = function (metric) { - var factor = metric ? 1 : 1 / 25; - return [ - steelseries.Section(0, 0.25 * factor, 'rgba(0, 140, 0, 0.5)'), - steelseries.Section(0.25 * factor, 1 * factor, 'rgba(80, 192, 80, 0.5)'), - steelseries.Section(1 * factor, 4 * factor, 'rgba(150, 203, 150, 0.5)'), - steelseries.Section(4 * factor, 16 * factor, 'rgba(212, 203, 109, 0.5)'), - steelseries.Section(16 * factor, 50 * factor, 'rgba(225, 155, 105, 0.5)'), - steelseries.Section(50 * factor, 1000 * factor, 'rgba(245, 86, 59, 0.5)') + // define UV start values + cache.value = 0.0001; + cache.sections = [ + steelseries.Section(0, 2.9, '#289500'), + steelseries.Section(2.9, 5.8, '#f7e400'), + steelseries.Section(5.8, 7.8, '#f85900'), + steelseries.Section(7.8, 10.9, '#d8001d'), + steelseries.Section(10.9, 20, '#6b49c8') ]; - }, - - // - // createRainFallSections()returns an array of section highlights for total rainfall in mm or inches - // - createRainfallSections = function (metric) { - var factor = metric ? 1 : 1 / 25; - return [ - steelseries.Section(0, 5 * factor, 'rgba(0, 250, 0, 1)'), - steelseries.Section(5 * factor, 10 * factor, 'rgba(0, 250, 117, 1)'), - steelseries.Section(10 * factor, 25 * factor, 'rgba(218, 246, 0, 1)'), - steelseries.Section(25 * factor, 40 * factor, 'rgba(250, 186, 0, 1)'), - steelseries.Section(40 * factor, 50 * factor, 'rgba(250, 95, 0, 1)'), - steelseries.Section(50 * factor, 65 * factor, 'rgba(250, 0, 0, 1)'), - steelseries.Section(65 * factor, 75 * factor, 'rgba(250, 6, 80, 1)'), - steelseries.Section(75 * factor, 100 * factor, 'rgba(205, 18, 158, 1)'), - steelseries.Section(100 * factor, 125 * factor, 'rgba(0, 0, 250, 1)'), - steelseries.Section(125 * factor, 500 * factor, 'rgba(0, 219, 212, 1)') - ]; - }, - - // - // createRainfallGradient() returns an array of SS colours for continuous gradient colouring of the total rainfall LED gauge - // - createRainfallGradient = function (metric) { - var grad = new steelseries.gradientWrapper( - 0, - (metric ? 100 : 4), - [0, 0.1, 0.62, 1], + // Define value gradient for UV + cache.gradient = new steelseries.gradientWrapper(0, 16, + [0, 0.1, 0.19, 0.31, 0.45, 0.625, 1], [ - new steelseries.rgbaColor(15, 148, 0, 1), - new steelseries.rgbaColor(213, 213, 0, 1), - new steelseries.rgbaColor(213, 0, 25, 1), - new steelseries.rgbaColor(250, 0, 0, 1) + new steelseries.rgbaColor(0, 200, 0, 1), + new steelseries.rgbaColor(0, 200, 0, 1), + new steelseries.rgbaColor(255, 255, 0, 1), + new steelseries.rgbaColor(248, 89, 0, 1), + new steelseries.rgbaColor(255, 0, 0, 1), + new steelseries.rgbaColor(255, 0, 144, 1), + new steelseries.rgbaColor(153, 140, 255, 1) ] ); - return grad; - }, + cache.useSections = false; + cache.useValueGradient = true; - // - // createClousBaseSections() returns an array of section highlights for the Cloud Base gauge - // - createCloudBaseSections = function (metric) { - var section; - if (metric) { - section = [ - steelseries.Section(0, 150, 'rgba(245, 86, 59, 0.5)'), - steelseries.Section(150, 300, 'rgba(225, 155, 105, 0.5)'), - steelseries.Section(300, 750, 'rgba(212, 203, 109, 0.5)'), - steelseries.Section(750, 1000, 'rgba(150, 203, 150, 0.5)'), - steelseries.Section(1000, 1500, 'rgba(80, 192, 80, 0.5)'), - steelseries.Section(1500, 2500, 'rgba(0, 140, 0, 0.5)'), - steelseries.Section(2500, 5500, 'rgba(19, 103, 186, 0.5)') - ]; + // create UV bargraph gauge + if ($('#canvas_uv').length) { + params.size = Math.ceil($('#canvas_uv').width() * config.gaugeScaling); + params.gaugeType = steelseries.GaugeType.TYPE3; + params.maxValue = gaugeGlobals.uvScaleDefMax; + params.titleString = strings.uv_title; + params.niceScale = false; + params.section = cache.sections; + params.useSectionColors = cache.useSections; + params.valueGradient = cache.gradient; + params.useValueGradient = cache.useValueGradient; + params.lcdDecimals = gaugeGlobals.uvLcdDecimals; + + ssGauge = new steelseries.RadialBargraph('canvas_uv', params); + ssGauge.setValue(cache.value); + + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_uv').css({ width: params.size + 'px', height: params.size + 'px' }); + } + + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_uv').css(gaugeShadow(params.size)); + } + + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); } else { - section = [ - steelseries.Section(0, 500, 'rgba(245, 86, 59, 0.5)'), - steelseries.Section(500, 1000, 'rgba(225, 155, 105, 0.5)'), - steelseries.Section(1000, 2500, 'rgba(212, 203, 109, 0.5)'), - steelseries.Section(2500, 3500, 'rgba(150, 203, 150, 0.5)'), - steelseries.Section(3500, 5500, 'rgba(80, 192, 80, 0.5)'), - steelseries.Section(5500, 8500, 'rgba(0, 140, 0, 0.5)'), - steelseries.Section(8500, 18000, 'rgba(19, 103, 186, 0.5)') - ]; + // cannot draw gauge, return null + return null; } - return section; - }, - // - // --------------- Helper functions ------------------ - // + function update() { + var tip, indx; - // - // getord() converts a value in degrees (0-360) into a localised compass point (N, ENE, NE, etc) - // - getord = function (deg) { - if (deg === 0) { - // Special case, 0=No wind, 360=North - return strings.calm; - } else { - return (strings.coords[Math.floor((deg + 11.25) / 22.5) % 16]); - } - }, + cache.value = extractDecimal(data.UV); - // - // getUrlParam() extracts the named parameter from the current page URL - // - getUrlParam = function (paramName) { - var name, regexS, regex, results; - name = paramName.replace(/(\[|\])/g, '\\$1'); - regexS = '[\\?&]' + name + '=([^&#]*)'; - regex = new RegExp(regexS); - results = regex.exec(window.location.href); - if (results === null) { - return ''; - } else { - return results[1]; - } - }, + if (+cache.value === 0) { + indx = 0; + } else if (cache.value < 2.5) { + indx = 1; + } else if (cache.value < 5.5) { + indx = 2; + } else if (cache.value < 7.5) { + indx = 3; + } else if (cache.value < 10.5) { + indx = 4; + } else { + indx = 5; + } - // - // extractDecimal() returns a decimal number from a string, the decimal point can be either a dot or a comma - // it ignores any text such as pre/appended units - // - extractDecimal = function (str, errVal) { - try { - return (/[-+]?[0-9]+\.?[0-9]*/).exec(str.replace(',', '.'))[0]; - } catch (e) { - // error condition - return errVal || -9999; - } - }, + cache.maxValue = Math.max(nextHighest(cache.value, 2), gaugeGlobals.uvScaleDefMax); + if (cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setValue(0); + ssGauge.setMaxValue(cache.maxValue); + } - // - // extractInteger() returns an integer from a string - // it ignores any text such as pre/appended units - // - extractInteger = function (str, errVal) { - try { - return (/[-+]?[0-9]+/).exec(str)[0]; - } catch (e) { - // error condition - return errVal || -9999; - } - }, + cache.risk = strings.uv_levels[indx]; + cache.headLine = strings.uv_headlines[indx]; + cache.detail = strings.uv_details[indx]; + ssGauge.setUnitString(cache.risk); + ssGauge.setValueAnimated(cache.value); - // - // tempTrend() converts a temperature trend value into a localised string, or +1, 0, -1 depending on the value of bTxt - // - tempTrend = function (trend, units, bTxt) { - // Scale is over 3 hours, in Celsius - var val = trend * 3 * (units[1] === 'C' ? 1 : (5 / 9)), - ret; - if (trend === -9999) { - ret = (bTxt ? '--' : trend); - } else if (val > 5) { - ret = (bTxt ? strings.RisingVeryRapidly : 1); - } else if (val > 3) { - ret = (bTxt ? strings.RisingQuickly : 1); - } else if (val > 1) { - ret = (bTxt ? strings.Rising : 1); - } else if (val > 0.5) { - ret = (bTxt ? strings.RisingSlowly : 1); - } else if (val >= -0.5) { - ret = (bTxt ? strings.Steady : 0); - } else if (val >= -1) { - ret = (bTxt ? strings.FallingSlowly : -1); - } else if (val >= -3) { - ret = (bTxt ? strings.Falling : -1); - } else if (val >= -5) { - ret = (bTxt ? strings.FallingQuickly : -1); - } else { - ret = (bTxt ? strings.FallingVeryRapidly : -1); - } - return ret; - }, + if (ddimgtooltip.showTips) { + // update tooltip + tip = '' + strings.uv_title + ': ' + cache.value + ' - ' + strings.solar_maxToday + ': ' + data.UVTH + '
'; + tip += '' + cache.headLine + '
'; + tip += cache.detail; + $('#imgtip8_txt').html(tip); + } + } // End of update() - // - // baroTrend() converts a pressure trend value into a localised string, or +1, 0, -1 depending on the value of bTxt - // - baroTrend = function (trend, units, bTxt) { - var val = trend * 3, - ret; - // The terms below are the UK Met Office terms for a 3 hour change in hPa - // trend is supplied as an hourly change, so multiply by 3 - if (units === 'inHg') { - val *= 33.8639; - } else if (units === 'kPa') { - val *= 10; - // assume everything else is hPa or mb, could be dangerous! - } - if (trend === -9999) { - ret = (bTxt ? '--' : trend); - } else if (val > 6.0) { - ret = (bTxt ? strings.RisingVeryRapidly : 1); - } else if (val > 3.5) { - ret = (bTxt ? strings.RisingQuickly : 1); - } else if (val > 1.5) { - ret = (bTxt ? strings.Rising : 1); - } else if (val > 0.1) { - ret = (bTxt ? strings.RisingSlowly : 1); - } else if (val >= -0.1) { - ret = (bTxt ? strings.Steady : 0); - } else if (val >= -1.5) { - ret = (bTxt ? strings.FallingSlowly : -1); - } else if (val >= -3.5) { - ret = (bTxt ? strings.Falling : -1); - } else if (val >= -6.0) { - ret = (bTxt ? strings.FallingQuickly : -1); - } else { - ret = (bTxt ? strings.FallingVeryRapidly : -1); - } - return ret; - }, - - // - // getMinTemp() returns the lowest temperature today for gauge scaling - // - getMinTemp = function (deflt) { - return Math.min( - extractDecimal(data.tempTL, deflt), - extractDecimal(data.dewpointTL, deflt), - extractDecimal(data.apptempTL, deflt), - extractDecimal(data.feelslikeTL, deflt), - extractDecimal(data.wchillTL, deflt)); - }, - - // - // getMaxTemp() returns the highest temperature today for gauge scaling - // - getMaxTemp = function (deflt) { - return Math.max( - extractDecimal(data.tempTH, deflt), - extractDecimal(data.apptempTH, deflt), - extractDecimal(data.feelslikeTH, deflt), - extractDecimal(data.heatindexTH, deflt), - extractDecimal(data.humidex, deflt)); - }, - - // Celsius to Fahrenheit - c2f = function (val) { - return (extractDecimal(val) * 9 / 5 + 32).toFixed(1); - }, - // Fahrenheit to Celsius - f2c = function (val) { - return ((extractDecimal(val) - 32) * 5 / 9).toFixed(1); - }, - // kph to ms - kmh2ms = function (val) { - return (extractDecimal(val) * 0.2778).toFixed(1); - }, - // ms to kph - ms2kmh = function (val) { - return (extractDecimal(val) * 3.6).toFixed(1); - }, - kmh2ms = function (val){ - return (extractDecimal(val) / 3.6).toFixed(1); - }, - // mm to inches - mm2in = function (val) { - return (extractDecimal(val) / 25.4).toFixed(2); - }, - // inches to mm - in2mm = function (val) { - return (extractDecimal(val) * 25.4).toFixed(1); - }, - // miles to km - miles2km = function (val) { - return (extractDecimal(val) * 1.609344).toFixed(1); - }, - // nautical miles to km - nmiles2km = function (val) { - return (extractDecimal(val) * 1.85200).toFixed(1); - }, - // km to miles - km2miles = function (val) { - return (extractDecimal(val) / 1.609344).toFixed(1); - }, - // km to nautical miles - km2nmiles = function (val) { - return (extractDecimal(val) / 1.85200).toFixed(1); - }, - // hPa to inHg (@0°C) - hpa2inhg = function (val, decimals) { - return (extractDecimal(val) * 0.029528744).toFixed(decimals || 3); - }, - // inHg to hPa (@0°C) - inhg2hpa = function (val) { - return (extractDecimal(val) / 0.029528744).toFixed(1); - }, - // kPa to hPa - kpa2hpa = function (val) { - return (extractDecimal(val) * 10).toFixed(1); - }, - // hPa to kPa - hpa2kpa = function (val, decimals) { - return (extractDecimal(val) / 10).toFixed(decimals || 2); - }, - // m to ft - m2ft = function (val) { - return (val * 3.2808399).toFixed(0); - }, - // ft to m - ft2m = function (val) { - return (val / 3.2808399).toFixed(0); - }, - - // - // setCookie() writes the 'obj' in cookie 'name' for persistent storage - // - setCookie = function (name, obj) { - var date = new Date(), - expires; - // cookies valid for 1 year - date.setYear(date.getFullYear() + 1); - expires = '; expires=' + date.toGMTString(); - document.cookie = name + '=' + encodeURIComponent(JSON.stringify(obj)) + expires; - }, - - // - // getCookie() reads the value of cookie 'name' from persistent storage - // - getCookie = function (name) { - var i, x, y, - ret = null, - arrCookies = document.cookie.split(';'); - - for (i = arrCookies.length; i--;) { - x = arrCookies[i].split('='); - if (x[0].trim() === name) { - try { - y = decodeURIComponent(x[1]); - } catch (e) { - y = x[1]; - } - ret = JSON.parse(unescape(y)); - break; + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[8] !== null) { + $('#imgtip8_img').attr('src', config.imgPathURL + config.tipImgs[8] + cacheDefeat); } } - return ret; - }, - // - // setRadioCheck() sets the desired value of the HTML radio buttons to be selected - // - setRadioCheck = function (obj, val) { - $('input:radio[name="' + obj + '"]').filter('[value="' + val + '"]').prop('checked', true); - }, + return { + update: update, + gauge: ssGauge + }; + } // End of init() - // - // convTempData() converts all the temperature values using the supplied conversion function - // - convTempData = function (convFunc) { - data.apptemp = convFunc(data.apptemp); - data.apptempTH = convFunc(data.apptempTH); - data.apptempTL = convFunc(data.apptempTL); - data.feelslike = convFunc(data.feelslike); - data.feelslikeTH = convFunc(data.feelslikeTH); - data.feelslikeTL = convFunc(data.feelslikeTL); - data.dew = convFunc(data.dew); - data.dewpointTH = convFunc(data.dewpointTH); - data.dewpointTL = convFunc(data.dewpointTL); - data.heatindex = convFunc(data.heatindex); - data.heatindexTH = convFunc(data.heatindexTH); - data.humidex = convFunc(data.humidex); - data.intemp = convFunc(data.intemp); - if (data.intempTL && data.intempTH) { - data.intempTL = convFunc(data.intempTL); - data.intempTH = convFunc(data.intempTH); + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; } - data.temp = convFunc(data.temp); - data.tempTH = convFunc(data.tempTH); - data.tempTL = convFunc(data.tempTL); - data.wchill = convFunc(data.wchill); - data.wchillTL = convFunc(data.wchillTL); - if (convFunc === c2f) { - data.temptrend = (+extractDecimal(data.temptrend) * 9 / 5).toFixed(1); - data.tempunit = '°F'; + }; + })(), + + // + // Singleton for the Solar Irradiation Gauge + // + singleSolar = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters + + function init() { + var params = $.extend(true, {}, commonParams); + + // define Solar start values + cache.value = 0.0001; + cache.sections = [ + steelseries.Section(0, 600, 'rgba(40,149,0,0.3)'), + steelseries.Section(600, 800, 'rgba(248,89,0,0.3)'), + steelseries.Section(800, 1000, 'rgba(216,0,29,0.3)'), + steelseries.Section(1000, 1800, 'rgba(107,73,200,0.3)') + ]; + + // create Solar gauge + if ($('#canvas_solar').length) { + params.size = Math.ceil($('#canvas_solar').width() * config.gaugeScaling); + params.section = cache.sections; + params.maxValue = gaugeGlobals.solarGaugeScaleMax; + params.titleString = strings.solar_title; + params.unitString = 'W/m\u00B2'; + params.niceScale = false; + params.thresholdVisible = false; + params.lcdDecimals = 0; + + if (config.showSunshineLed) { + params.userLedVisible = true; + params.userLedColor = steelseries.LedColor.YELLOW_LED; + } + + ssGauge = new steelseries.Radial('canvas_solar', params); + ssGauge.setValue(cache.value); + + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_solar').css({ width: params.size + 'px', height: params.size + 'px' }); + } + + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_solar').css(gaugeShadow(params.size)); + } + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); } else { - data.temptrend = (+extractDecimal(data.temptrend) * 5 / 9).toFixed(1); - data.tempunit = '°C'; + // cannot draw gauge, return null + return null; } - }, - // - // convRainData() converts all the rain data units using the supplied conversion function - // - convRainData = function (convFunc) { - data.rfall = convFunc(data.rfall); - data.rrate = convFunc(data.rrate); - data.rrateTM = convFunc(data.rrateTM); - data.hourlyrainTH = convFunc(data.hourlyrainTH); - data.rainunit = convFunc === mm2in ? 'in' : 'mm'; - }, + function update() { + var tip, percent; - // - // convWindData() converts all the wind values using the supplied conversion function - // - convWindData = function (from, to) { - var fromFunc1, toFunc1, - fromFunc2, toFunc2, - dummy = function (val) { - return val; - }; + cache.value = +extractInteger(data.SolarRad); + cache.maxToday = extractInteger(data.SolarTM); + cache.currMaxValue = +extractInteger(data.CurrentSolarMax); + percent = (+cache.currMaxValue === 0 ? '--' : Math.round(+cache.value / +cache.currMaxValue * 100)); - // convert to km/h & km - switch (from) { + // Need to rescale the gauge? + cache.maxValue = Math.max(cache.value, cache.currMaxValue, cache.maxToday, gaugeGlobals.solarGaugeScaleMax); + cache.maxValue = nextHighest(cache.maxValue, 100); + if (cache.maxValue !== ssGauge.getMaxValue()) { + ssGauge.setValue(0); + ssGauge.setMaxValue(cache.maxValue); + } + + // Set a section (15% of maxScale wide) to show current theoretical max value + if (data.CurrentSolarMax !== 'N/A') { + ssGauge.setArea([ + // Sunshine threshold + steelseries.Section( + Math.max(cache.currMaxValue * gaugeGlobals.sunshineThresholdPct / 100, gaugeGlobals.sunshineThreshold), + cache.currMaxValue, + 'rgba(255,255,50,0.4)' + ), + // Over max threshold + steelseries.Section( + cache.currMaxValue, + Math.min(cache.currMaxValue + cache.maxValue * 0.15, cache.maxValue), + 'rgba(220,0,0,0.5)' + ) + ]); + } + + // Set the values + ssGauge.setMaxMeasuredValue(cache.maxToday); + ssGauge.setValueAnimated(cache.value); + + if (config.showSunshineLed) { + ssGauge.setUserLedOnOff( + percent !== '--' && + percent >= gaugeGlobals.sunshineThresholdPct && + +cache.value >= gaugeGlobals.sunshineThreshold + ); + } + + if (ddimgtooltip.showTips) { + // update tooltip + tip = '' + strings.solar_title + ': ' + cache.value + ' W/m² - ' + + '' + percent + '% ' + strings.solar_ofMax + '
' + + strings.solar_currentMax + ': ' + cache.currMaxValue + ' W/m²'; + if (typeof data.SolarTM !== 'undefined') { + tip += '
' + strings.solar_maxToday + ': ' + cache.maxToday + ' W/m²'; + } + $('#imgtip9_txt').html(tip); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[9] !== null) { + $('#imgtip9_img').attr('src', config.imgPathURL + config.tipImgs[9] + cacheDefeat); + } + } + + return { + update: update, + gauge: ssGauge + }; + } // End of init() + + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), + + // + // Singleton for the Cloudbase Gauge + // + singleCloudBase = (function () { + var instance; // Stores a reference to the Singleton + var ssGauge; // Stores a reference to the SS Gauge + var cache = {}; // Stores various config values and parameters + + function init() { + var params = $.extend(true, {}, commonParams); + + cache.sections = createCloudBaseSections(true); + cache.value = 0.0001; + cache.maxValue = gaugeGlobals.cloudScaleDefMaxm; + + // create Cloud base radial gauge + if ($('#canvas_cloud').length) { + params.size = Math.ceil($('#canvas_cloud').width() * config.gaugeScaling); + params.section = cache.sections; + params.maxValue = cache.maxValue; + params.titleString = strings.cloudbase_title; + params.unitString = strings.metres; + params.thresholdVisible = false; + params.lcdDecimals = 0; + + ssGauge = new steelseries.Radial('canvas_cloud', params); + ssGauge.setValue(cache.value); + + // over-ride CSS applied size? + if (config.gaugeScaling !== 1) { + $('#canvas_cloud').css({ width: params.size + 'px', height: params.size + 'px' }); + } + + // add a shadow to the gauge + if (config.showGaugeShadow) { + $('#canvas_cloud').css(gaugeShadow(params.size)); + } + // subscribe to data updates + $.subscribe('gauges.dataUpdated', update); + $.subscribe('gauges.graphUpdate', updateGraph); + } else { + // cannot draw gauge, return null + return null; + } + + function update() { + cache.value = extractInteger(data.cloudbasevalue); + + if (data.cloudbaseunit === 'm') { + // adjust metre gauge in jumps of 1000 metres, don't downscale during the session + cache.maxValue = Math.max(nextHighest(cache.value, 1000), gaugeGlobals.cloudScaleDefMaxm, cache.maxValue); + if (cache.value <= 1000 && config.roundCloudbaseVal) { + // and round the value to the nearest 10 m + cache.value = Math.round(cache.value / 10) * 10; + } else if (config.roundCloudbaseVal) { + // and round the value to the nearest 50 m + cache.value = Math.round(cache.value / 50) * 50; + } + } else { + // adjust feet gauge in jumps of 2000 ft, don't downscale during the session + cache.maxValue = Math.max(nextHighest(cache.value, 2000), gaugeGlobals.cloudScaleDefMaxft, cache.maxValue); + if (cache.value <= 2000 && config.roundCloudbaseVal) { + // and round the value to the nearest 50 ft + cache.value = Math.round(cache.value / 50) * 50; + } else if (config.roundCloudbaseVal) { + // and round the value to the nearest 100 ft + cache.value = Math.round(cache.value / 100) * 100; + } + } + + if (cache.maxValue !== ssGauge.getMaxValue()) { + if (ssGauge.getMaxValue() > cache.maxValue) { + // Gauge currently showing more than our max (nice scale effct), + // so reset our max to match + cache.maxValue = ssGauge.getMaxValue(); + } else { + // Gauge scale is too low, increase it. + // First set the pointer back to zero so we get a nice animation + ssGauge.setValue(0); + // and redraw the gauge with teh new scale + ssGauge.setMaxValue(cache.maxValue); + } + } + ssGauge.setValueAnimated(cache.value); + + if (config.showPopupData) { + // static tooltip on cloud gauge + $('#imgtip11_txt').html('' + strings.cloudbase_popup_title + '
' + strings.cloudbase_popup_text); + } + } // End of update() + + function updateGraph(evnt, cacheDefeat) { + if (config.tipImgs[11] !== null) { + $('#imgtip11_img').attr('src', config.imgPathURL + config.tipImgs[11] + cacheDefeat); + } + } + + return { + data: cache, + update: update, + gauge: ssGauge + }; + } // End of init() + + return { + // Get the Singleton instance if one exists + // or create one if it doesn't + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; + })(), + + // + // getRealtime() fetches the realtimegauges JSON data from the server + // + getRealtime = function () { + var url = config.realTimeURL; + if ($.active > 0 && undefined != jqXHR) { + // kill any outstanding requests + jqXHR.abort(); + } + if (config.longPoll) { + url += '?timestamp=' + timestamp; + } + jqXHR = $.ajax({ + url: url, + cache: (config.longPoll), + dataType: 'json', + timeout: config.longPoll ? (Math.min(config.realtimeInterval, 20) + 21) * 1000 : 21000 // 21 second time-out by default + }).done(function (data) { + checkRtResp(data); + }).fail(function (xhr, status, err) { + checkRtError(xhr, status, err); + }); + }, + + // + // checkRtResp() called by the Ajax fetch once data has been downloaded + // + checkRtResp = function (response) { + var delay; + statusTimer.reset(config.longPoll ? 1 : config.realtimeInterval); + if (config.longPoll && response.status !== 'OK') { + checkRtError(null, 'PHP Error', response.status); + } else { + if (processData(response)) { + delay = ajaxDelay; + } else { + delay = 5; + } + if (delay > 0) { + downloadTimer = setTimeout(getRealtime, delay * 1000); + } else { + getRealtime(); + } + } + }, + + // + // checkRtError() called by the Ajax fetch if an error occurs during the fetching realtimegauges.txt + // + checkRtError = function (xhr, status, error) { + if (xhr == null || xhr.statusText !== 'abort') { + // Clear any existing download timer + clearTimeout(downloadTimer); + // Set the status LED to off + ledIndicator.setLedOnOff(false); + ledIndicator.setTitle(strings.led_title_unknown); + statusScroller.setText(status + ': ' + error); + // wait 5 seconds, then try again... + downloadTimer = setTimeout(getRealtime, 5000); + } + }, + + // + // processData() massages the data returned in realtimegauges.txt, and posts a gauges.dataUpdated event to update the page + // + processData = function (dataObj) { + var str, dt, tm, today, now, then, tmp, elapsedMins, retVal; + // copy the realtime fields into the global 'data' object + if (config.longPoll) { + timestamp = dataObj.timestamp; + data = dataObj.data; + } else { + // normal polling + data = dataObj; + } + + // and check we have the expected version number + if (typeof data.ver !== 'undefined' && data.ver >= realtimeVer) { + // manpulate the last rain time into something more friendly + try { + str = data.LastRainTipISO.split(' '); + dt = str[0].replace(/\//g, '-').split('-'); // WD uses dd/mm/yyyy, we use a '-' + tm = str[1].split(':'); + today = new Date(); + today.setHours(0, 0, 0, 0); + if (typeof data.dateFormat === 'undefined') { + data.dateFormat = 'y/m/d'; + } else { + // frig for WD bug which leaves a trailing % character from the tag + data.dateFormat = data.dateFormat.replace('%', ''); + } + if (data.dateFormat === 'y/m/d') { + // ISO/Cumulus format + then = new Date(dt[0], dt[1] - 1, dt[2], tm[0], tm[1], 0, 0); + } else if (data.dateFormat === 'd/m/y') { + then = new Date(dt[2], dt[1] - 1, dt[0], tm[0], tm[1], 0, 0); + } else { // m/d/y + then = new Date(dt[2], dt[0] - 1, dt[1], tm[0], tm[1], 0, 0); + } + if (then.getTime() >= today.getTime()) { + data.LastRained = strings.LastRainedT_info + ' ' + str[1]; + } else if (then.getTime() + 86400000 >= today.getTime()) { + data.LastRained = strings.LastRainedY_info + ' ' + str[1]; + } else { + data.LastRained = then.getDate().toString() + ' ' + strings.months[then.getMonth()] + ' ' + strings.at + ' ' + str[1]; + } + } catch (e) { + data.LastRained = data.LastRainTipISO; + } + if (data.tempunit.length > 1) { + // clean up temperature units - remove html encoded degree symbols + data.tempunit = data.tempunit.replace(/&\S*;/, '°'); // old Cumulus versions uses °, WeatherCat uses ° + } else { + // using new realtimegaugesT.txt with Cumulus > 1.9.2 + data.tempunit = '°' + data.tempunit; + } + + // Check for station off-line + now = Date.now(); + tmp = data.timeUTC.split(','); + sampleDate = Date.UTC(tmp[0], tmp[1] - 1, tmp[2], tmp[3], tmp[4], tmp[5]); + if (now - sampleDate > config.stationTimeout * 60 * 1000) { + elapsedMins = Math.floor((now - sampleDate) / (1000 * 60)); + // the realtimegauges.txt file isn't being updated + ledIndicator.setLedColor(steelseries.LedColor.RED_LED); + ledIndicator.setTitle(strings.led_title_offline); + ledIndicator.blink(true); + if (elapsedMins < 120) { + // up to 2 hours ago + tm = elapsedMins.toString() + ' ' + strings.StatusMinsAgo; + } else if (elapsedMins < 2 * 24 * 60) { + // up to 48 hours ago + tm = Math.floor(elapsedMins / 60).toString() + ' ' + strings.StatusHoursAgo; + } else { + // days ago! + tm = Math.floor(elapsedMins / (60 * 24)).toString() + ' ' + strings.StatusDaysAgo; + } + data.forecast = strings.led_title_offline + ' ' + strings.StatusLastUpdate + ' ' + tm; + } else if (+data.SensorContactLost === 1) { + // Fine Offset sensor status + ledIndicator.setLedColor(steelseries.LedColor.RED_LED); + ledIndicator.setTitle(strings.led_title_lost); + ledIndicator.blink(true); + data.forecast = strings.led_title_lost; + } else { + ledIndicator.setLedColor(steelseries.LedColor.GREEN_LED); + ledIndicator.setTitle(strings.led_title_ok + '. ' + strings.StatusLastUpdate + ': ' + data.date); + ledIndicator.blink(false); + ledIndicator.setLedOnOff(true); + } + + // de-encode the forecast string if required (Cumulus support for extended characters) + data.forecast = $('
').html(data.forecast).text(); + data.forecast = data.forecast.trim(); + + data.pressunit = data.pressunit.trim(); // WView sends ' in', ' mb', or ' hPa' + if (data.pressunit === 'in') { // Cumulus and WView send 'in' + data.pressunit = 'inHg'; + } + + data.windunit = data.windunit.trim(); // WView sends ' kmh' etc + data.windunit = data.windunit.toLowerCase(); // WeatherCat sends "MPH" + if (data.windunit === 'knots') { // WeatherCat/weewx send "Knots", we use "kts" + data.windunit = 'kts'; + } + + if (data.windunit === 'kmh' || data.windunit === 'kph') { // WD wind unit omits '/', weewx sends 'kph' + data.windunit = 'km/h'; + } + + data.rainunit = data.rainunit.trim(); // WView sends ' mm' etc + + // take a look at the cloud base data... + // change WeatherCat units from Metres/Feet to m/ft + try { + if (data.cloudbaseunit.toLowerCase() === 'metres') { + data.cloudbaseunit = 'm'; + } else if (data.cloudbaseunit.toLowerCase() === 'feet') { + data.cloudbaseunit = 'ft'; + } + } catch (e) { + data.cloudbaseunit = ''; + } + if (config.showCloudGauge && ( + (config.weatherProgram === 4 || config.weatherProgram === 5) || + data.cloudbasevalue === '')) { + // WeatherCat and VWS (and WView?) do not provide a cloud base value, so we have to calculate it... + // assume if the station uses an imperial wind speed they want cloud base in feet, otherwise metres + data.cloudbaseunit = (data.windunit === 'mph' || data.windunit === 'kts') ? 'ft' : 'm'; + data.cloudbasevalue = calcCloudbase(data.temp, data.tempunit, data.dew, data.cloudbaseunit); + } + + // Temperature data conversion for display required? + if (data.tempunit[1] !== displayUnits.temp && userUnitsSet) { + // temp needs converting + if (data.tempunit[1] === 'C') { + convTempData(c2f); + } else { + convTempData(f2c); + } + } else if (firstRun) { + displayUnits.temp = data.tempunit[1]; + setRadioCheck('rad_unitsTemp', displayUnits.temp); + } + + // Rain data conversion for display required? + if (data.rainunit !== displayUnits.rain && userUnitsSet) { + // rain needs converting + convRainData(displayUnits.rain === 'mm' ? in2mm : mm2in); + } else if (firstRun) { + displayUnits.rain = data.rainunit; + setRadioCheck('rad_unitsRain', displayUnits.rain); + } + + // Wind data conversion for display required? + if (data.windunit !== displayUnits.wind && userUnitsSet) { + // wind needs converting + convWindData(data.windunit, displayUnits.wind); + } else if (firstRun) { + displayUnits.wind = data.windunit; + displayUnits.windrun = getWindrunUnits(data.windunit); + setRadioCheck('rad_unitsWind', displayUnits.wind); + } + + // Pressure data conversion for display required? + if (data.pressunit !== displayUnits.press && userUnitsSet) { + convBaroData(data.pressunit, displayUnits.press); + } else if (firstRun) { + displayUnits.press = data.pressunit; + setRadioCheck('rad_unitsPress', displayUnits.press); + } + + // Cloud height data conversion for display required? + if (data.cloudbaseunit !== displayUnits.cloud && userUnitsSet) { + // Cloud height needs converting + convCloudBaseData(displayUnits.cloud === 'm' ? ft2m : m2ft); + } else if (firstRun) { + displayUnits.cloud = data.cloudbaseunit; + setRadioCheck('rad_unitsCloud', displayUnits.cloud); + } + + statusScroller.setText(data.forecast); + + // first time only, setup units etc + if (firstRun) { + doFirst(); + } + + // publish the update, use the shared data object rather than transferring it + $.publish('gauges.dataUpdated', {}); + + retVal = true; + } else { + // set an error message + if (data.ver < realtimeVer) { + statusTimer.setValue(0); + statusScroller.setText('Your ' + config.realTimeURL.substr(config.realTimeURL.lastIndexOf('/') + 1) + ' file template needs updating!'); + return false; + } else { + // oh-oh! The number of data fields isn't what we expected + statusScroller.setText(strings.realtimeCorrupt); + } + ledIndicator.setLedOnOff(false); + ledIndicator.setTitle(strings.led_title_unknown); + + retVal = false; + } + return retVal; + }, + + // + // pagetimeout() called once every config.pageUpdateLimit minutes to stop updates and prevent page 'sitters' + // + pageTimeout = function () { + statusScroller.setText(strings.StatusPageLimit); + ledIndicator.setLedColor(steelseries.LedColor.RED_LED); + ledIndicator.setTitle(strings.StatusPageLimit); + ledIndicator.blink(true); + ledIndicator.setTitle(strings.StatusTimeout); + + // stop any pending download + clearTimeout(downloadTimer); + + // stop any long polling in progress + if ($.active > 0) { + jqXHR.abort(); + } + + // stop the clock + clearInterval(tickTockInterval); + + // clear the timer display + statusTimer.setValue(0); + + // set an onclick event on the LED to restart everything + $('#canvas_led').click( + function click() { + // disable the onClick event again + $('#canvas_led').unbind('click'); + // reset the timer count to 1 + statusTimer.reset(1); + // restart the timer to update the status time + tickTockInterval = setInterval( + function tick() { + $.publish('gauges.clockTick', null); + }, + 1000 + ); + + // restart the page timeout timer, so we hit this code again + setTimeout(pageTimeout, config.pageUpdateLimit * 60 * 1000); + + // refresh the page data + getRealtime(); + } + ); + }, + + // + // doFirst() called by doUpdate() the first time the page is updated to set-up various things that are + // only known when the realtimegauges.txt data is available + // + doFirst = function () { + var cacheDefeat = '?' + (new Date()).getTime().toString(); + + if (data.tempunit[1] === 'F') { + displayUnits.temp = 'F'; + setRadioCheck('rad_unitsTemp', 'F'); + setTempUnits(false); + } + + if (data.pressunit !== 'hPa') { + displayUnits.press = data.pressunit; + setRadioCheck('rad_unitsPress', data.pressunit); + setBaroUnits(data.pressunit); + } + + if (data.windunit !== 'km/h') { + displayUnits.wind = data.windunit; + setRadioCheck('rad_unitsWind', data.windunit); + setWindUnits(data.windunit); + } + + if (data.rainunit !== 'mm') { + displayUnits.rain = data.rainunit; + setRadioCheck('rad_unitsRain', data.rainunit); + setRainUnits(false); + } + + if (config.showSolarGauge && typeof data.SolarTM !== 'undefined' && gaugeSolar) { + gaugeSolar.gauge.setMaxMeasuredValueVisible(true); + } + + if (config.showCloudGauge && data.cloudbaseunit !== 'm') { + displayUnits.cloud = data.cloudbaseunit; + setRadioCheck('rad_unitsCloud', data.cloudbaseunit); + setCloudBaseUnits(false); + } + + // set the script version on the page + $('#scriptVer').html(config.scriptVer); + // set the version information from the station + $('#programVersion').html(data.version); + $('#programBuild').html(data.build); + $('#programName').html(programLink[config.weatherProgram]); + + if (config.showPopupData) { + // now initialise the pop-up script and download the trend /images + // - has to be done here as doFirst may remove elements from the page + // - and we delay the download of the /images speeding up page display + ddimgtooltip.init('[id^="tip_"]'); + // Are we running on a phone device (or really low res screen)? + if ($(window).width() < 480) { + $('.ddimgtooltip').filter(':hidden').width('200px'); + } + } + + if (config.showPopupData && config.showPopupGraphs) { + // now download the trend /images + // - has to be done here as doFirst may remove elements from the page + // - and we delay the download of the /images speeding up page display + // + $('#imgtip0_img').attr('src', config.imgPathURL + config.tipImgs[0][0] + cacheDefeat); + if (gaugeDew) { + $('#imgtip1_img').attr('src', config.imgPathURL + config.tipImgs[1][gaugeDew.data.popupImg] + cacheDefeat); + } + $('#imgtip2_img').attr('src', config.imgPathURL + config.tipImgs[2] + cacheDefeat); + $('#imgtip3_img').attr('src', config.imgPathURL + config.tipImgs[3] + cacheDefeat); + $('#imgtip4_img').attr('src', config.imgPathURL + config.tipImgs[4][0] + cacheDefeat); + $('#imgtip5_img').attr('src', config.imgPathURL + config.tipImgs[5] + cacheDefeat); + $('#imgtip6_img').attr('src', config.imgPathURL + config.tipImgs[6] + cacheDefeat); + $('#imgtip7_img').attr('src', config.imgPathURL + config.tipImgs[7] + cacheDefeat); + $('#imgtip8_img').attr('src', config.imgPathURL + config.tipImgs[8] + cacheDefeat); + $('#imgtip9_img').attr('src', config.imgPathURL + config.tipImgs[9] + cacheDefeat); + $('#imgtip10_img').attr('src', config.imgPathURL + config.tipImgs[10] + cacheDefeat); + $('#imgtip11_img').attr('src', config.imgPathURL + config.tipImgs[11] + cacheDefeat); + // start a timer for popup graphic updates + setInterval( + function timeout() { + $.publish('gauges.graphUpdate', '?' + (new Date()).getTime().toString()); + }, + config.graphUpdateTime * 60 * 1000 + ); + } + + firstRun = false; + }, + + // + // createTempSections() creates an array of gauge sections appropriate for Celsius or Fahrenheit scales + // + createTempSections = function (celsius) { + var section; + if (celsius) { + section = [ + steelseries.Section(-100, -35, 'rgba(195, 92, 211, 0.4)'), + steelseries.Section(-35, -30, 'rgba(139, 74, 197, 0.4)'), + steelseries.Section(-30, -25, 'rgba(98, 65, 188, 0.4)'), + steelseries.Section(-25, -20, 'rgba(62, 66, 185, 0.4)'), + steelseries.Section(-20, -15, 'rgba(42, 84, 194, 0.4)'), + steelseries.Section(-15, -10, 'rgba(25, 112, 210, 0.4)'), + steelseries.Section(-10, -5, 'rgba(9, 150, 224, 0.4)'), + steelseries.Section(-5, 0, 'rgba(2, 170, 209, 0.4)'), + steelseries.Section(0, 5, 'rgba(0, 162, 145, 0.4)'), + steelseries.Section(5, 10, 'rgba(0, 158, 122, 0.4)'), + steelseries.Section(10, 15, 'rgba(54, 177, 56, 0.4)'), + steelseries.Section(15, 20, 'rgba(111, 202, 56, 0.4)'), + steelseries.Section(20, 25, 'rgba(248, 233, 45, 0.4)'), + steelseries.Section(25, 30, 'rgba(253, 142, 42, 0.4)'), + steelseries.Section(30, 40, 'rgba(236, 45, 45, 0.4)'), + steelseries.Section(40, 100, 'rgba(245, 109, 205, 0.4)') + ]; + } else { + section = [ + steelseries.Section(-200, -30, 'rgba(195, 92, 211, 0.4)'), + steelseries.Section(-30, -25, 'rgba(139, 74, 197, 0.4)'), + steelseries.Section(-25, -15, 'rgba(98, 65, 188, 0.4)'), + steelseries.Section(-15, -5, 'rgba(62, 66, 185, 0.4)'), + steelseries.Section(-5, 5, 'rgba(42, 84, 194, 0.4)'), + steelseries.Section(5, 15, 'rgba(25, 112, 210, 0.4)'), + steelseries.Section(15, 25, 'rgba(9, 150, 224, 0.4)'), + steelseries.Section(25, 32, 'rgba(2, 170, 209, 0.4)'), + steelseries.Section(32, 40, 'rgba(0, 162, 145, 0.4)'), + steelseries.Section(40, 50, 'rgba(0, 158, 122, 0.4)'), + steelseries.Section(50, 60, 'rgba(54, 177, 56, 0.4)'), + steelseries.Section(60, 70, 'rgba(111, 202, 56, 0.4)'), + steelseries.Section(70, 80, 'rgba(248, 233, 45, 0.4)'), + steelseries.Section(80, 90, 'rgba(253, 142, 42, 0.4)'), + steelseries.Section(90, 110, 'rgba(236, 45, 45, 0.4)'), + steelseries.Section(110, 200, 'rgba(245, 109, 205, 0.4)') + ]; + } + return section; + }, + + // + // createRainSections() returns an array of section highlights for the Rain Rate gauge + // + /* + Assumes 'standard' descriptive limits from UK met office: + < 0.25 mm/hr - Very light rain + 0.25mm/hr to 1.0mm/hr - Light rain + 1.0 mm/hr to 4.0 mm/hr - Moderate rain + 4.0 mm/hr to 16.0 mm/hr - Heavy rain + 16.0 mm/hr to 50 mm/hr - Very heavy rain + > 50.0 mm/hour - Extreme rain + + Roughly translated to the corresponding Inch rates + < 0.001 + 0.001 to 0.05 + 0.05 to 0.20 + 0.20 to 0.60 + 0.60 to 2.0 + > 2.0 + */ + createRainRateSections = function (metric) { + var factor = metric ? 1 : 1 / 25; + return [ + steelseries.Section(0, 0.25 * factor, 'rgba(0, 140, 0, 0.5)'), + steelseries.Section(0.25 * factor, 1 * factor, 'rgba(80, 192, 80, 0.5)'), + steelseries.Section(1 * factor, 4 * factor, 'rgba(150, 203, 150, 0.5)'), + steelseries.Section(4 * factor, 16 * factor, 'rgba(212, 203, 109, 0.5)'), + steelseries.Section(16 * factor, 50 * factor, 'rgba(225, 155, 105, 0.5)'), + steelseries.Section(50 * factor, 1000 * factor, 'rgba(245, 86, 59, 0.5)') + ]; + }, + + // + // createRainFallSections()returns an array of section highlights for total rainfall in mm or inches + // + createRainfallSections = function (metric) { + var factor = metric ? 1 : 1 / 25; + return [ + steelseries.Section(0, 5 * factor, 'rgba(0, 250, 0, 1)'), + steelseries.Section(5 * factor, 10 * factor, 'rgba(0, 250, 117, 1)'), + steelseries.Section(10 * factor, 25 * factor, 'rgba(218, 246, 0, 1)'), + steelseries.Section(25 * factor, 40 * factor, 'rgba(250, 186, 0, 1)'), + steelseries.Section(40 * factor, 50 * factor, 'rgba(250, 95, 0, 1)'), + steelseries.Section(50 * factor, 65 * factor, 'rgba(250, 0, 0, 1)'), + steelseries.Section(65 * factor, 75 * factor, 'rgba(250, 6, 80, 1)'), + steelseries.Section(75 * factor, 100 * factor, 'rgba(205, 18, 158, 1)'), + steelseries.Section(100 * factor, 125 * factor, 'rgba(0, 0, 250, 1)'), + steelseries.Section(125 * factor, 500 * factor, 'rgba(0, 219, 212, 1)') + ]; + }, + + // + // createRainfallGradient() returns an array of SS colours for continuous gradient colouring of the total rainfall LED gauge + // + createRainfallGradient = function (metric) { + var grad = new steelseries.gradientWrapper( + 0, + (metric ? 100 : 4), + [0, 0.1, 0.62, 1], + [ + new steelseries.rgbaColor(15, 148, 0, 1), + new steelseries.rgbaColor(213, 213, 0, 1), + new steelseries.rgbaColor(213, 0, 25, 1), + new steelseries.rgbaColor(250, 0, 0, 1) + ] + ); + return grad; + }, + + // + // createClousBaseSections() returns an array of section highlights for the Cloud Base gauge + // + createCloudBaseSections = function (metric) { + var section; + if (metric) { + section = [ + steelseries.Section(0, 150, 'rgba(245, 86, 59, 0.5)'), + steelseries.Section(150, 300, 'rgba(225, 155, 105, 0.5)'), + steelseries.Section(300, 750, 'rgba(212, 203, 109, 0.5)'), + steelseries.Section(750, 1000, 'rgba(150, 203, 150, 0.5)'), + steelseries.Section(1000, 1500, 'rgba(80, 192, 80, 0.5)'), + steelseries.Section(1500, 2500, 'rgba(0, 140, 0, 0.5)'), + steelseries.Section(2500, 5500, 'rgba(19, 103, 186, 0.5)') + ]; + } else { + section = [ + steelseries.Section(0, 500, 'rgba(245, 86, 59, 0.5)'), + steelseries.Section(500, 1000, 'rgba(225, 155, 105, 0.5)'), + steelseries.Section(1000, 2500, 'rgba(212, 203, 109, 0.5)'), + steelseries.Section(2500, 3500, 'rgba(150, 203, 150, 0.5)'), + steelseries.Section(3500, 5500, 'rgba(80, 192, 80, 0.5)'), + steelseries.Section(5500, 8500, 'rgba(0, 140, 0, 0.5)'), + steelseries.Section(8500, 18000, 'rgba(19, 103, 186, 0.5)') + ]; + } + return section; + }, + + // + // --------------- Helper functions ------------------ + // + + // + // getord() converts a value in degrees (0-360) into a localised compass point (N, ENE, NE, etc) + // + getord = function (deg) { + if (deg === 0) { + // Special case, 0=No wind, 360=North + return strings.calm; + } else { + return (strings.coords[Math.floor((deg + 11.25) / 22.5) % 16]); + } + }, + + // + // getUrlParam() extracts the named parameter from the current page URL + // + getUrlParam = function (paramName) { + var name, regexS, regex, results; + name = paramName.replace(/(\[|\])/g, '\\$1'); + regexS = '[\\?&]' + name + '=([^&#]*)'; + regex = new RegExp(regexS); + results = regex.exec(window.location.href); + if (results === null) { + return ''; + } else { + return results[1]; + } + }, + + // + // extractDecimal() returns a decimal number from a string, the decimal point can be either a dot or a comma + // it ignores any text such as pre/appended units + // + extractDecimal = function (str, errVal) { + try { + return (/[-+]?[0-9]+\.?[0-9]*/).exec(str.replace(',', '.'))[0]; + } catch (e) { + // error condition + return errVal || -9999; + } + }, + + // + // extractInteger() returns an integer from a string + // it ignores any text such as pre/appended units + // + extractInteger = function (str, errVal) { + try { + return (/[-+]?[0-9]+/).exec(str)[0]; + } catch (e) { + // error condition + return errVal || -9999; + } + }, + + // + // tempTrend() converts a temperature trend value into a localised string, or +1, 0, -1 depending on the value of bTxt + // + tempTrend = function (trend, units, bTxt) { + // Scale is over 3 hours, in Celsius + var val = trend * 3 * (units[1] === 'C' ? 1 : (5 / 9)), + ret; + if (trend === -9999) { + ret = (bTxt ? '--' : trend); + } else if (val > 5) { + ret = (bTxt ? strings.RisingVeryRapidly : 1); + } else if (val > 3) { + ret = (bTxt ? strings.RisingQuickly : 1); + } else if (val > 1) { + ret = (bTxt ? strings.Rising : 1); + } else if (val > 0.5) { + ret = (bTxt ? strings.RisingSlowly : 1); + } else if (val >= -0.5) { + ret = (bTxt ? strings.Steady : 0); + } else if (val >= -1) { + ret = (bTxt ? strings.FallingSlowly : -1); + } else if (val >= -3) { + ret = (bTxt ? strings.Falling : -1); + } else if (val >= -5) { + ret = (bTxt ? strings.FallingQuickly : -1); + } else { + ret = (bTxt ? strings.FallingVeryRapidly : -1); + } + return ret; + }, + + // + // baroTrend() converts a pressure trend value into a localised string, or +1, 0, -1 depending on the value of bTxt + // + baroTrend = function (trend, units, bTxt) { + var val = trend * 3, + ret; + // The terms below are the UK Met Office terms for a 3 hour change in hPa + // trend is supplied as an hourly change, so multiply by 3 + if (units === 'inHg') { + val *= 33.8639; + } else if (units === 'kPa') { + val *= 10; + // assume everything else is hPa or mb, could be dangerous! + } + if (trend === -9999) { + ret = (bTxt ? '--' : trend); + } else if (val > 6.0) { + ret = (bTxt ? strings.RisingVeryRapidly : 1); + } else if (val > 3.5) { + ret = (bTxt ? strings.RisingQuickly : 1); + } else if (val > 1.5) { + ret = (bTxt ? strings.Rising : 1); + } else if (val > 0.1) { + ret = (bTxt ? strings.RisingSlowly : 1); + } else if (val >= -0.1) { + ret = (bTxt ? strings.Steady : 0); + } else if (val >= -1.5) { + ret = (bTxt ? strings.FallingSlowly : -1); + } else if (val >= -3.5) { + ret = (bTxt ? strings.Falling : -1); + } else if (val >= -6.0) { + ret = (bTxt ? strings.FallingQuickly : -1); + } else { + ret = (bTxt ? strings.FallingVeryRapidly : -1); + } + return ret; + }, + + // + // getMinTemp() returns the lowest temperature today for gauge scaling + // + getMinTemp = function (deflt) { + return Math.min( + extractDecimal(data.tempTL, deflt), + extractDecimal(data.dewpointTL, deflt), + extractDecimal(data.apptempTL, deflt), + extractDecimal(data.feelslikeTL, deflt), + extractDecimal(data.wchillTL, deflt)); + }, + + // + // getMaxTemp() returns the highest temperature today for gauge scaling + // + getMaxTemp = function (deflt) { + return Math.max( + extractDecimal(data.tempTH, deflt), + extractDecimal(data.apptempTH, deflt), + extractDecimal(data.feelslikeTH, deflt), + extractDecimal(data.heatindexTH, deflt), + extractDecimal(data.humidex, deflt)); + }, + + // Celsius to Fahrenheit + c2f = function (val) { + return (extractDecimal(val) * 9 / 5 + 32).toFixed(1); + }, + // Fahrenheit to Celsius + f2c = function (val) { + return ((extractDecimal(val) - 32) * 5 / 9).toFixed(1); + }, + // kph to ms + kmh2ms = function (val) { + return (extractDecimal(val) * 0.2778).toFixed(1); + }, + // ms to kph + ms2kmh = function (val) { + return (extractDecimal(val) * 3.6).toFixed(1); + }, + kmh2ms = function (val) { + return (extractDecimal(val) / 3.6).toFixed(1); + }, + // mm to inches + mm2in = function (val) { + return (extractDecimal(val) / 25.4).toFixed(2); + }, + // inches to mm + in2mm = function (val) { + return (extractDecimal(val) * 25.4).toFixed(1); + }, + // miles to km + miles2km = function (val) { + return (extractDecimal(val) * 1.609344).toFixed(1); + }, + // nautical miles to km + nmiles2km = function (val) { + return (extractDecimal(val) * 1.85200).toFixed(1); + }, + // km to miles + km2miles = function (val) { + return (extractDecimal(val) / 1.609344).toFixed(1); + }, + // km to nautical miles + km2nmiles = function (val) { + return (extractDecimal(val) / 1.85200).toFixed(1); + }, + // hPa to inHg (@0°C) + hpa2inhg = function (val, decimals) { + return (extractDecimal(val) * 0.029528744).toFixed(decimals || 3); + }, + // inHg to hPa (@0°C) + inhg2hpa = function (val) { + return (extractDecimal(val) / 0.029528744).toFixed(1); + }, + // kPa to hPa + kpa2hpa = function (val) { + return (extractDecimal(val) * 10).toFixed(1); + }, + // hPa to kPa + hpa2kpa = function (val, decimals) { + return (extractDecimal(val) / 10).toFixed(decimals || 2); + }, + // m to ft + m2ft = function (val) { + return (val * 3.2808399).toFixed(0); + }, + // ft to m + ft2m = function (val) { + return (val / 3.2808399).toFixed(0); + }, + + // + // setCookie() writes the 'obj' in cookie 'name' for persistent storage + // + setCookie = function (name, obj) { + var date = new Date(), + expires; + // cookies valid for 1 year + date.setYear(date.getFullYear() + 1); + expires = '; expires=' + date.toGMTString(); + document.cookie = name + '=' + encodeURIComponent(JSON.stringify(obj)) + expires; + }, + + // + // getCookie() reads the value of cookie 'name' from persistent storage + // + getCookie = function (name) { + var i, x, y, + ret = null, + arrCookies = document.cookie.split(';'); + + for (i = arrCookies.length; i--;) { + x = arrCookies[i].split('='); + if (x[0].trim() === name) { + try { + y = decodeURIComponent(x[1]); + } catch (e) { + y = x[1]; + } + ret = JSON.parse(unescape(y)); + break; + } + } + return ret; + }, + + // + // setRadioCheck() sets the desired value of the HTML radio buttons to be selected + // + setRadioCheck = function (obj, val) { + $('input:radio[name="' + obj + '"]').filter('[value="' + val + '"]').prop('checked', true); + }, + + // + // convTempData() converts all the temperature values using the supplied conversion function + // + convTempData = function (convFunc) { + data.apptemp = convFunc(data.apptemp); + data.apptempTH = convFunc(data.apptempTH); + data.apptempTL = convFunc(data.apptempTL); + data.feelslike = convFunc(data.feelslike); + data.feelslikeTH = convFunc(data.feelslikeTH); + data.feelslikeTL = convFunc(data.feelslikeTL); + data.dew = convFunc(data.dew); + data.dewpointTH = convFunc(data.dewpointTH); + data.dewpointTL = convFunc(data.dewpointTL); + data.heatindex = convFunc(data.heatindex); + data.heatindexTH = convFunc(data.heatindexTH); + data.humidex = convFunc(data.humidex); + data.intemp = convFunc(data.intemp); + if (data.intempTL && data.intempTH) { + data.intempTL = convFunc(data.intempTL); + data.intempTH = convFunc(data.intempTH); + } + data.temp = convFunc(data.temp); + data.tempTH = convFunc(data.tempTH); + data.tempTL = convFunc(data.tempTL); + data.wchill = convFunc(data.wchill); + data.wchillTL = convFunc(data.wchillTL); + if (convFunc === c2f) { + data.temptrend = (+extractDecimal(data.temptrend) * 9 / 5).toFixed(1); + data.tempunit = '°F'; + } else { + data.temptrend = (+extractDecimal(data.temptrend) * 5 / 9).toFixed(1); + data.tempunit = '°C'; + } + }, + + // + // convRainData() converts all the rain data units using the supplied conversion function + // + convRainData = function (convFunc) { + data.rfall = convFunc(data.rfall); + data.rrate = convFunc(data.rrate); + data.rrateTM = convFunc(data.rrateTM); + data.hourlyrainTH = convFunc(data.hourlyrainTH); + data.rainunit = convFunc === mm2in ? 'in' : 'mm'; + }, + + // + // convWindData() converts all the wind values using the supplied conversion function + // + convWindData = function (from, to) { + var fromFunc1, toFunc1, + fromFunc2, toFunc2, + dummy = function (val) { + return val; + }; + + // convert to km/h & km + switch (from) { case 'mph': fromFunc1 = miles2km; fromFunc2 = miles2km; @@ -3637,9 +3638,9 @@ gauges = (function () { default: fromFunc1 = dummy; fromFunc2 = dummy; - } - // conversion function from km to required units - switch (to) { + } + // conversion function from km to required units + switch (to) { case 'mph': toFunc1 = km2miles; toFunc2 = km2miles; @@ -3661,28 +3662,28 @@ gauges = (function () { toFunc1 = dummy; toFunc2 = dummy; displayUnits.windrun = 'km'; - } - // do the conversions - data.wgust = toFunc1(fromFunc1(data.wgust)); - data.wgustTM = toFunc1(fromFunc1(data.wgustTM)); - data.windTM = toFunc1(fromFunc1(data.windTM)); - data.windrun = toFunc2(fromFunc2(data.windrun)); - data.wlatest = toFunc1(fromFunc1(data.wlatest)); - data.wspeed = toFunc1(fromFunc1(data.wspeed)); - data.windunit = to; - }, + } + // do the conversions + data.wgust = toFunc1(fromFunc1(data.wgust)); + data.wgustTM = toFunc1(fromFunc1(data.wgustTM)); + data.windTM = toFunc1(fromFunc1(data.windTM)); + data.windrun = toFunc2(fromFunc2(data.windrun)); + data.wlatest = toFunc1(fromFunc1(data.wlatest)); + data.wspeed = toFunc1(fromFunc1(data.wspeed)); + data.windunit = to; + }, - // - // convBaroData() converts all the pressure values using the supplied conversion function - // - convBaroData = function (from, to) { - var fromFunc, toFunc, - dummy = function (val) { - return val; - }; + // + // convBaroData() converts all the pressure values using the supplied conversion function + // + convBaroData = function (from, to) { + var fromFunc, toFunc, + dummy = function (val) { + return val; + }; - // convert to hPa - switch (from) { + // convert to hPa + switch (from) { case 'hPa': // falls through case 'mb': @@ -3695,9 +3696,9 @@ gauges = (function () { fromFunc = kpa2hpa; break; // no default - } - // convert to required units - switch (to) { + } + // convert to required units + switch (to) { case 'hPa': // falls through case 'mb': @@ -3710,42 +3711,42 @@ gauges = (function () { toFunc = hpa2kpa; break; // no default - } + } - data.press = toFunc(fromFunc(data.press)); - data.pressH = toFunc(fromFunc(data.pressH)); - data.pressL = toFunc(fromFunc(data.pressL)); - data.pressTH = toFunc(fromFunc(data.pressTH)); - data.pressTL = toFunc(fromFunc(data.pressTL)); - data.presstrendval = toFunc(fromFunc(data.presstrendval), 3); - data.pressunit = to; - }, + data.press = toFunc(fromFunc(data.press)); + data.pressH = toFunc(fromFunc(data.pressH)); + data.pressL = toFunc(fromFunc(data.pressL)); + data.pressTH = toFunc(fromFunc(data.pressTH)); + data.pressTL = toFunc(fromFunc(data.pressTL)); + data.presstrendval = toFunc(fromFunc(data.presstrendval), 3); + data.pressunit = to; + }, - // - // convCloudBaseData() converts all the cloud base data units using the supplied conversion function - // - convCloudBaseData = function (convFunc) { - data.cloudbasevalue = convFunc(data.cloudbasevalue); - data.cloudbaseunit = convFunc === m2ft ? 'ft' : 'm'; - }, + // + // convCloudBaseData() converts all the cloud base data units using the supplied conversion function + // + convCloudBaseData = function (convFunc) { + data.cloudbasevalue = convFunc(data.cloudbasevalue); + data.cloudbaseunit = convFunc === m2ft ? 'ft' : 'm'; + }, - // - // setUnits() Main data conversion routine, calls all the setXXXX() sub-routines - // - setUnits = function (radio) { - var sel = radio.value; + // + // setUnits() Main data conversion routine, calls all the setXXXX() sub-routines + // + setUnits = function (radio) { + var sel = radio.value; - userUnitsSet = true; + userUnitsSet = true; - switch (sel) { + switch (sel) { // == Temperature == case 'C': displayUnits.temp = sel; if (data.tempunit[1] !== sel) { setTempUnits(true); convTempData(f2c); - if (gaugeTemp) {gaugeTemp.update();} - if (gaugeDew) {gaugeDew.update();} + if (gaugeTemp) { gaugeTemp.update(); } + if (gaugeDew) { gaugeDew.update(); } } break; case 'F': @@ -3753,8 +3754,8 @@ gauges = (function () { if (data.tempunit[1] !== sel) { setTempUnits(false); convTempData(c2f); - if (gaugeTemp) {gaugeTemp.update();} - if (gaugeDew) {gaugeDew.update();} + if (gaugeTemp) { gaugeTemp.update(); } + if (gaugeDew) { gaugeDew.update(); } } break; // == Rainfall == @@ -3763,8 +3764,8 @@ gauges = (function () { if (data.rainunit !== sel) { setRainUnits(true); convRainData(in2mm); - if (gaugeRain) {gaugeRain.update();} - if (gaugeRRate) {gaugeRRate.update();} + if (gaugeRain) { gaugeRain.update(); } + if (gaugeRRate) { gaugeRRate.update(); } } break; case 'in': @@ -3772,8 +3773,8 @@ gauges = (function () { if (data.rainunit !== sel) { setRainUnits(false); convRainData(mm2in); - if (gaugeRain) {gaugeRain.update();} - if (gaugeRRate) {gaugeRRate.update();} + if (gaugeRain) { gaugeRain.update(); } + if (gaugeRRate) { gaugeRRate.update(); } } break; // == Pressure == @@ -3788,7 +3789,7 @@ gauges = (function () { if (data.pressunit !== sel) { convBaroData(data.pressunit, sel); setBaroUnits(sel); - if (gaugeBaro) {gaugeBaro.update();} + if (gaugeBaro) { gaugeBaro.update(); } } break; // == Wind speed == @@ -3803,9 +3804,9 @@ gauges = (function () { if (data.windunit !== sel) { convWindData(data.windunit, sel); setWindUnits(sel); - if (gaugeWind) {gaugeWind.update();} - if (gaugeDir) {gaugeDir.update();} - if (gaugeRose) {gaugeRose.update();} + if (gaugeWind) { gaugeWind.update(); } + if (gaugeDir) { gaugeDir.update(); } + if (gaugeRose) { gaugeRose.update(); } } break; // == CloudBase == @@ -3814,7 +3815,7 @@ gauges = (function () { if (data.cloudbaseunit !== sel) { setCloudBaseUnits(true); convCloudBaseData(ft2m); - if (gaugeCloud) {gaugeCloud.update();} + if (gaugeCloud) { gaugeCloud.update(); } } break; case 'ft': @@ -3822,117 +3823,117 @@ gauges = (function () { if (data.cloudbaseunit !== sel) { setCloudBaseUnits(false); convCloudBaseData(m2ft); - if (gaugeCloud) {gaugeCloud.update();} + if (gaugeCloud) { gaugeCloud.update(); } } break; // no default - } - if (config.useCookies) { - setCookie('units', displayUnits); - } - }, + } + if (config.useCookies) { + setCookie('units', displayUnits); + } + }, - setTempUnits = function (celsius) { - if (celsius) { - data.tempunit = '°C'; - if (gaugeTemp) { - gaugeTemp.data.sections = createTempSections(true); - gaugeTemp.data.minValue = gaugeGlobals.tempScaleDefMinC; - gaugeTemp.data.maxValue = gaugeGlobals.tempScaleDefMaxC; - } - if (gaugeDew) { - gaugeDew.data.sections = createTempSections(true); - gaugeDew.data.minValue = gaugeGlobals.tempScaleDefMinC; - gaugeDew.data.maxValue = gaugeGlobals.tempScaleDefMaxC; - } - } else { - data.tempunit = '°F'; - if (gaugeTemp) { - gaugeTemp.data.sections = createTempSections(false); - gaugeTemp.data.minValue = gaugeGlobals.tempScaleDefMinF; - gaugeTemp.data.maxValue = gaugeGlobals.tempScaleDefMaxF; - } - if (gaugeDew) { - gaugeDew.data.sections = createTempSections(false); - gaugeDew.data.minValue = gaugeGlobals.tempScaleDefMinF; - gaugeDew.data.maxValue = gaugeGlobals.tempScaleDefMaxF; - } - } + setTempUnits = function (celsius) { + if (celsius) { + data.tempunit = '°C'; if (gaugeTemp) { - gaugeTemp.gauge.setUnitString(data.tempunit); - gaugeTemp.gauge.setSection(gaugeTemp.data.sections); + gaugeTemp.data.sections = createTempSections(true); + gaugeTemp.data.minValue = gaugeGlobals.tempScaleDefMinC; + gaugeTemp.data.maxValue = gaugeGlobals.tempScaleDefMaxC; } if (gaugeDew) { - gaugeDew.gauge.setUnitString(data.tempunit); - gaugeDew.gauge.setSection(gaugeTemp.data.sections); + gaugeDew.data.sections = createTempSections(true); + gaugeDew.data.minValue = gaugeGlobals.tempScaleDefMinC; + gaugeDew.data.maxValue = gaugeGlobals.tempScaleDefMaxC; } - }, + } else { + data.tempunit = '°F'; + if (gaugeTemp) { + gaugeTemp.data.sections = createTempSections(false); + gaugeTemp.data.minValue = gaugeGlobals.tempScaleDefMinF; + gaugeTemp.data.maxValue = gaugeGlobals.tempScaleDefMaxF; + } + if (gaugeDew) { + gaugeDew.data.sections = createTempSections(false); + gaugeDew.data.minValue = gaugeGlobals.tempScaleDefMinF; + gaugeDew.data.maxValue = gaugeGlobals.tempScaleDefMaxF; + } + } + if (gaugeTemp) { + gaugeTemp.gauge.setUnitString(data.tempunit); + gaugeTemp.gauge.setSection(gaugeTemp.data.sections); + } + if (gaugeDew) { + gaugeDew.gauge.setUnitString(data.tempunit); + gaugeDew.gauge.setSection(gaugeTemp.data.sections); + } + }, - setRainUnits = function (mm) { - if (mm) { - data.rainunit = 'mm'; - if (gaugeRain) { - gaugeRain.data.lcdDecimals = 1; - gaugeRain.data.scaleDecimals = 1; - gaugeRain.data.labelNumberFormat = gaugeGlobals.labelFormat; - gaugeRain.data.sections = (gaugeGlobals.rainUseSectionColours ? createRainfallSections(true) : []); - gaugeRain.data.maxValue = gaugeGlobals.rainScaleDefMaxmm; - gaugeRain.data.grad = (gaugeGlobals.rainUseGradientColours ? createRainfallGradient(true) : null); - } - if (gaugeRRate) { - gaugeRRate.data.lcdDecimals = 1; - gaugeRRate.data.scaleDecimals = 0; - gaugeRRate.data.labelNumberFormat = gaugeGlobals.labelFormat; - gaugeRRate.data.sections = createRainRateSections(true); - gaugeRRate.data.maxValue = gaugeGlobals.rainRateScaleDefMaxmm; - } - } else { - data.rainunit = 'in'; - if (gaugeRain) { - gaugeRain.data.lcdDecimals = 2; - gaugeRain.data.scaleDecimals = gaugeGlobals.rainScaleDefMaxIn < 1 ? 2 : 1; - gaugeRain.data.labelNumberFormat = steelseries.LabelNumberFormat.FRACTIONAL; - gaugeRain.data.sections = (gaugeGlobals.rainUseSectionColours ? createRainfallSections(false) : []); - gaugeRain.data.maxValue = gaugeGlobals.rainScaleDefMaxIn; - gaugeRain.data.grad = (gaugeGlobals.rainUseGradientColours ? createRainfallGradient(false) : null); - } - if (gaugeRRate) { - gaugeRRate.data.lcdDecimals = 2; - gaugeRRate.data.scaleDecimals = gaugeGlobals.rainRateScaleDefMaxIn < 1 ? 2 : 1; - gaugeRRate.data.labelNumberFormat = steelseries.LabelNumberFormat.FRACTIONAL; - gaugeRRate.data.sections = createRainRateSections(false); - gaugeRRate.data.maxValue = gaugeGlobals.rainRateScaleDefMaxIn; - } - } + setRainUnits = function (mm) { + if (mm) { + data.rainunit = 'mm'; if (gaugeRain) { - gaugeRain.data.value = 0; - gaugeRain.gauge.setUnitString(data.rainunit); - gaugeRain.gauge.setSection(gaugeRain.data.sections); - gaugeRain.gauge.setGradient(gaugeRain.data.grad); - gaugeRain.gauge.setFractionalScaleDecimals(gaugeRain.data.scaleDecimals); - gaugeRain.gauge.setLabelNumberFormat(gaugeRain.data.labelNumberFormat); - gaugeRain.gauge.setLcdDecimals(gaugeRain.data.lcdDecimals); - gaugeRain.gauge.setValue(0); - gaugeRain.gauge.setMaxValue(gaugeRain.data.maxValue); + gaugeRain.data.lcdDecimals = 1; + gaugeRain.data.scaleDecimals = 1; + gaugeRain.data.labelNumberFormat = gaugeGlobals.labelFormat; + gaugeRain.data.sections = (gaugeGlobals.rainUseSectionColours ? createRainfallSections(true) : []); + gaugeRain.data.maxValue = gaugeGlobals.rainScaleDefMaxmm; + gaugeRain.data.grad = (gaugeGlobals.rainUseGradientColours ? createRainfallGradient(true) : null); } if (gaugeRRate) { - gaugeRRate.data.value = 0; - gaugeRRate.gauge.setUnitString(data.rainunit + '/h'); - gaugeRRate.gauge.setSection(gaugeRRate.data.sections); - gaugeRRate.gauge.setFractionalScaleDecimals(gaugeRRate.data.scaleDecimals); - gaugeRRate.gauge.setLabelNumberFormat(gaugeRRate.data.labelNumberFormat); - gaugeRRate.gauge.setLcdDecimals(gaugeRRate.data.lcdDecimals); - gaugeRRate.gauge.setValue(0); - gaugeRRate.gauge.setMaxValue(gaugeRRate.data.maxValue); + gaugeRRate.data.lcdDecimals = 1; + gaugeRRate.data.scaleDecimals = 0; + gaugeRRate.data.labelNumberFormat = gaugeGlobals.labelFormat; + gaugeRRate.data.sections = createRainRateSections(true); + gaugeRRate.data.maxValue = gaugeGlobals.rainRateScaleDefMaxmm; } - }, + } else { + data.rainunit = 'in'; + if (gaugeRain) { + gaugeRain.data.lcdDecimals = 2; + gaugeRain.data.scaleDecimals = gaugeGlobals.rainScaleDefMaxIn < 1 ? 2 : 1; + gaugeRain.data.labelNumberFormat = steelseries.LabelNumberFormat.FRACTIONAL; + gaugeRain.data.sections = (gaugeGlobals.rainUseSectionColours ? createRainfallSections(false) : []); + gaugeRain.data.maxValue = gaugeGlobals.rainScaleDefMaxIn; + gaugeRain.data.grad = (gaugeGlobals.rainUseGradientColours ? createRainfallGradient(false) : null); + } + if (gaugeRRate) { + gaugeRRate.data.lcdDecimals = 2; + gaugeRRate.data.scaleDecimals = gaugeGlobals.rainRateScaleDefMaxIn < 1 ? 2 : 1; + gaugeRRate.data.labelNumberFormat = steelseries.LabelNumberFormat.FRACTIONAL; + gaugeRRate.data.sections = createRainRateSections(false); + gaugeRRate.data.maxValue = gaugeGlobals.rainRateScaleDefMaxIn; + } + } + if (gaugeRain) { + gaugeRain.data.value = 0; + gaugeRain.gauge.setUnitString(data.rainunit); + gaugeRain.gauge.setSection(gaugeRain.data.sections); + gaugeRain.gauge.setGradient(gaugeRain.data.grad); + gaugeRain.gauge.setFractionalScaleDecimals(gaugeRain.data.scaleDecimals); + gaugeRain.gauge.setLabelNumberFormat(gaugeRain.data.labelNumberFormat); + gaugeRain.gauge.setLcdDecimals(gaugeRain.data.lcdDecimals); + gaugeRain.gauge.setValue(0); + gaugeRain.gauge.setMaxValue(gaugeRain.data.maxValue); + } + if (gaugeRRate) { + gaugeRRate.data.value = 0; + gaugeRRate.gauge.setUnitString(data.rainunit + '/h'); + gaugeRRate.gauge.setSection(gaugeRRate.data.sections); + gaugeRRate.gauge.setFractionalScaleDecimals(gaugeRRate.data.scaleDecimals); + gaugeRRate.gauge.setLabelNumberFormat(gaugeRRate.data.labelNumberFormat); + gaugeRRate.gauge.setLcdDecimals(gaugeRRate.data.lcdDecimals); + gaugeRRate.gauge.setValue(0); + gaugeRRate.gauge.setMaxValue(gaugeRRate.data.maxValue); + } + }, - setWindUnits = function (to) { - var maxVal; - data.windunit = to; - if (gaugeWind) { - // conversion function to required units - switch (to) { + setWindUnits = function (to) { + var maxVal; + data.windunit = to; + if (gaugeWind) { + // conversion function to required units + switch (to) { case 'mph': maxVal = gaugeGlobals.windScaleDefMaxMph; break; @@ -3946,24 +3947,24 @@ gauges = (function () { maxVal = gaugeGlobals.windScaleDefMaxMs; break; // no default - } - // set the gauges - gaugeWind.data.maxValue = maxVal; - gaugeWind.gauge.setUnitString(data.windunit); - gaugeWind.gauge.setValue(0); } - if (gaugeRose) { - gaugeRose.setOdoTitle(strings[getWindrunUnits(data.windunit)]); - } - }, + // set the gauges + gaugeWind.data.maxValue = maxVal; + gaugeWind.gauge.setUnitString(data.windunit); + gaugeWind.gauge.setValue(0); + } + if (gaugeRose) { + gaugeRose.setOdoTitle(strings[getWindrunUnits(data.windunit)]); + } + }, - setBaroUnits = function (to) { - var minVal, maxVal; + setBaroUnits = function (to) { + var minVal, maxVal; - if (!gaugeBaro) {return;} + if (!gaugeBaro) { return; } - // set to the required units - switch (to) { + // set to the required units + switch (to) { case 'hPa': // falls through case 'mb': @@ -3988,56 +3989,56 @@ gauges = (function () { gaugeBaro.data.labelNumberFormat = steelseries.LabelNumberFormat.FRACTIONAL; break; // no default - } + } - data.pressunit = to; - gaugeBaro.gauge.setUnitString(to); - gaugeBaro.gauge.setLcdDecimals(gaugeBaro.data.lcdDecimals); - gaugeBaro.gauge.setFractionalScaleDecimals(gaugeBaro.data.scaleDecimals); - gaugeBaro.gauge.setLabelNumberFormat(gaugeBaro.data.labelNumberFormat); - gaugeBaro.data.minValue = minVal; - gaugeBaro.data.maxValue = maxVal; - gaugeBaro.data.value = gaugeBaro.data.minValue; - }, + data.pressunit = to; + gaugeBaro.gauge.setUnitString(to); + gaugeBaro.gauge.setLcdDecimals(gaugeBaro.data.lcdDecimals); + gaugeBaro.gauge.setFractionalScaleDecimals(gaugeBaro.data.scaleDecimals); + gaugeBaro.gauge.setLabelNumberFormat(gaugeBaro.data.labelNumberFormat); + gaugeBaro.data.minValue = minVal; + gaugeBaro.data.maxValue = maxVal; + gaugeBaro.data.value = gaugeBaro.data.minValue; + }, - setCloudBaseUnits = function (m) { - if (!gaugeCloud) {return;} + setCloudBaseUnits = function (m) { + if (!gaugeCloud) { return; } - if (m) { - gaugeCloud.data.sections = createCloudBaseSections(true); - gaugeCloud.data.maxValue = gaugeGlobals.cloudScaleDefMaxm; - } else { - gaugeCloud.data.sections = createCloudBaseSections(false); - gaugeCloud.data.maxValue = gaugeGlobals.cloudScaleDefMaxft; - } - gaugeCloud.data.value = 0; - gaugeCloud.gauge.setUnitString(m ? strings.metres : strings.feet); - gaugeCloud.gauge.setSection(gaugeCloud.data.sections); - }, + if (m) { + gaugeCloud.data.sections = createCloudBaseSections(true); + gaugeCloud.data.maxValue = gaugeGlobals.cloudScaleDefMaxm; + } else { + gaugeCloud.data.sections = createCloudBaseSections(false); + gaugeCloud.data.maxValue = gaugeGlobals.cloudScaleDefMaxft; + } + gaugeCloud.data.value = 0; + gaugeCloud.gauge.setUnitString(m ? strings.metres : strings.feet); + gaugeCloud.gauge.setSection(gaugeCloud.data.sections); + }, - // - // setLang() switches the HTML page language set, called by changeLang() in language.js - // - setLang = function (newLang) { - // reset to the new language - strings = newLang; + // + // setLang() switches the HTML page language set, called by changeLang() in language.js + // + setLang = function (newLang) { + // reset to the new language + strings = newLang; - // temperature - if (gaugeTemp) { - if (config.showIndoorTempHum) { - if ($('#rad_temp1').is(':checked')) { - gaugeTemp.data.title = strings.temp_title_out; - } else { - gaugeTemp.data.title = strings.temp_title_in; - } - } else { + // temperature + if (gaugeTemp) { + if (config.showIndoorTempHum) { + if ($('#rad_temp1').is(':checked')) { gaugeTemp.data.title = strings.temp_title_out; + } else { + gaugeTemp.data.title = strings.temp_title_in; } - gaugeTemp.gauge.setTitleString(gaugeTemp.data.title); - if (data.ver) {gaugeTemp.update();} + } else { + gaugeTemp.data.title = strings.temp_title_out; } - if (gaugeDew) { - switch ($('input[name="rad_dew"]:checked').val()) { + gaugeTemp.gauge.setTitleString(gaugeTemp.data.title); + if (data.ver) { gaugeTemp.update(); } + } + if (gaugeDew) { + switch ($('input[name="rad_dew"]:checked').val()) { case 'dew': gaugeDew.data.title = strings.dew_title; break; @@ -4057,83 +4058,83 @@ gauges = (function () { gaugeDew.data.title = strings.humdx_title; break; // no default - } - gaugeDew.gauge.setTitleString(gaugeDew.data.title); - if (data.ver) {gaugeDew.update();} } - // rain - if (gaugeRain) { - gaugeRain.data.title = strings.rain_title; - gaugeRain.gauge.setTitleString(gaugeRain.data.title); - if (data.ver) {gaugeRain.update();} - } - // rrate - if (gaugeRRate) { - gaugeRRate.data.title = strings.rrate_title; - gaugeRRate.gauge.setTitleString(gaugeRRate.data.title); - if (data.ver) {gaugeRRate.update();} - } - // humidity - if (gaugeHum) { - if (config.showIndoorTempHum) { - if ($('#rad_hum1').is(':checked')) { - gaugeHum.data.title = strings.hum_title_out; - } else { - gaugeHum.data.title = strings.hum_title_in; - } - } else { + gaugeDew.gauge.setTitleString(gaugeDew.data.title); + if (data.ver) { gaugeDew.update(); } + } + // rain + if (gaugeRain) { + gaugeRain.data.title = strings.rain_title; + gaugeRain.gauge.setTitleString(gaugeRain.data.title); + if (data.ver) { gaugeRain.update(); } + } + // rrate + if (gaugeRRate) { + gaugeRRate.data.title = strings.rrate_title; + gaugeRRate.gauge.setTitleString(gaugeRRate.data.title); + if (data.ver) { gaugeRRate.update(); } + } + // humidity + if (gaugeHum) { + if (config.showIndoorTempHum) { + if ($('#rad_hum1').is(':checked')) { gaugeHum.data.title = strings.hum_title_out; + } else { + gaugeHum.data.title = strings.hum_title_in; } - gaugeHum.gauge.setTitleString(gaugeHum.data.title); - if (data.ver) {gaugeHum.update();} + } else { + gaugeHum.data.title = strings.hum_title_out; } - // barometer - if (gaugeBaro) { - gaugeBaro.data.title = strings.baro_title; - gaugeBaro.gauge.setTitleString(gaugeBaro.data.title); - if (data.ver) {gaugeBaro.update();} - } - // wind - if (gaugeWind) { - gaugeWind.data.title = strings.wind_title; - gaugeWind.gauge.setTitleString(gaugeWind.data.title); - if (data.ver) {gaugeWind.update();} - } - if (gaugeDir) { - gaugeDir.gauge.setPointSymbols(strings.compass); - gaugeDir.data.titles = [strings.latest_web, strings.tenminavg_web]; - gaugeDir.gauge.setLcdTitleStrings(gaugeDir.data.titles); - if (data.ver) {gaugeDir.update();} - } - if (gaugeUV) { - gaugeUV.gauge.setTitleString(strings.uv_title); - if (data.ver) {gaugeUV.update();} - } - if (gaugeSolar) { - gaugeSolar.gauge.setTitleString(strings.solar_title); - if (data.ver) {gaugeSolar.update();} - } - if (gaugeRose) { - gaugeRose.setTitle(strings.windrose); - gaugeRose.setCompassStrings(strings.compass); - gaugeRose.setOdoTitle(strings[getWindrunUnits(displayUnits.wind)]); - if (data.ver) {gaugeRose.update();} - } - if (gaugeCloud) { - // Cloudbase - gaugeCloud.data.units = data.cloudunit === 'm' ? strings.metres : strings.feet; - gaugeCloud.gauge.setTitleString(strings.cloudbase_title); - gaugeCloud.gauge.setUnitString(gaugeCloud.data.units); - if (data.ver) {gaugeCloud.update();} - } - }, + gaugeHum.gauge.setTitleString(gaugeHum.data.title); + if (data.ver) { gaugeHum.update(); } + } + // barometer + if (gaugeBaro) { + gaugeBaro.data.title = strings.baro_title; + gaugeBaro.gauge.setTitleString(gaugeBaro.data.title); + if (data.ver) { gaugeBaro.update(); } + } + // wind + if (gaugeWind) { + gaugeWind.data.title = strings.wind_title; + gaugeWind.gauge.setTitleString(gaugeWind.data.title); + if (data.ver) { gaugeWind.update(); } + } + if (gaugeDir) { + gaugeDir.gauge.setPointSymbols(strings.compass); + gaugeDir.data.titles = [strings.latest_web, strings.tenminavg_web]; + gaugeDir.gauge.setLcdTitleStrings(gaugeDir.data.titles); + if (data.ver) { gaugeDir.update(); } + } + if (gaugeUV) { + gaugeUV.gauge.setTitleString(strings.uv_title); + if (data.ver) { gaugeUV.update(); } + } + if (gaugeSolar) { + gaugeSolar.gauge.setTitleString(strings.solar_title); + if (data.ver) { gaugeSolar.update(); } + } + if (gaugeRose) { + gaugeRose.setTitle(strings.windrose); + gaugeRose.setCompassStrings(strings.compass); + gaugeRose.setOdoTitle(strings[getWindrunUnits(displayUnits.wind)]); + if (data.ver) { gaugeRose.update(); } + } + if (gaugeCloud) { + // Cloudbase + gaugeCloud.data.units = data.cloudunit === 'm' ? strings.metres : strings.feet; + gaugeCloud.gauge.setTitleString(strings.cloudbase_title); + gaugeCloud.gauge.setUnitString(gaugeCloud.data.units); + if (data.ver) { gaugeCloud.update(); } + } + }, - // - // return windrun units based on the windspeed units - // - getWindrunUnits = function (spdUnits) { - var retVal; - switch (spdUnits) { + // + // return windrun units based on the windspeed units + // + getWindrunUnits = function (spdUnits) { + var retVal; + switch (spdUnits) { case 'mph': retVal = 'miles'; break; @@ -4147,119 +4148,119 @@ gauges = (function () { default: retVal = 'km'; break; - } - return retVal; - }, + } + return retVal; + }, - // - // performs a simple cloudbase calculation for those weather programs that don't supply it - // - calcCloudbase = function (temp, tempunit, dew, cloudbaseunit) { - var sprd = temp - dew; - var cb = sprd * (tempunit[1] === 'C' ? 400 : 227.3); // cloud base in feet - if (cloudbaseunit === 'm') { - cb = ft2m(cb); - } - return cb; - }, + // + // performs a simple cloudbase calculation for those weather programs that don't supply it + // + calcCloudbase = function (temp, tempunit, dew, cloudbaseunit) { + var sprd = temp - dew; + var cb = sprd * (tempunit[1] === 'C' ? 400 : 227.3); // cloud base in feet + if (cloudbaseunit === 'm') { + cb = ft2m(cb); + } + return cb; + }, - // - // create a shadow effect for the gauge using CSS - // - gaugeShadow = function (size) { - var offset = Math.floor(size * 0.015); - return { - 'box-shadow' : offset + 'px ' + offset + 'px ' + offset + 'px ' + gaugeGlobals.shadowColour, - 'border-radius': Math.floor(size / 2) + 'px' - }; - }, - - // - // generate a colour gradient based on start and end values - // - gradient = function (startCol, endCol, fraction) { - var redOrigin, grnOrigin, bluOrigin, - gradientSizeRed, gradientSizeGrn, gradientSizeBlu; - - redOrigin = parseInt(startCol.substr(0, 2), 16); - grnOrigin = parseInt(startCol.substr(2, 2), 16); - bluOrigin = parseInt(startCol.substr(4, 2), 16); - - gradientSizeRed = parseInt(endCol.substr(0, 2), 16) - redOrigin; // Graduation Size Red - gradientSizeGrn = parseInt(endCol.substr(2, 2), 16) - grnOrigin; - gradientSizeBlu = parseInt(endCol.substr(4, 2), 16) - bluOrigin; - - return (redOrigin + (gradientSizeRed * fraction)).toFixed(0) + ',' + - (grnOrigin + (gradientSizeGrn * fraction)).toFixed(0) + ',' + - (bluOrigin + (gradientSizeBlu * fraction)).toFixed(0); - }, - // - // returns the next highest number in the step sequence - // - nextHighest = function (value, step) { - return +value == 0 ? step : Math.ceil(+value / step) * step; - }, - // - // returns the next lowest number in the step sequence - // - nextLowest = function (value, step) { - return +value == 0 ? -step : Math.floor(+value / step) * step; + // + // create a shadow effect for the gauge using CSS + // + gaugeShadow = function (size) { + var offset = Math.floor(size * 0.015); + return { + 'box-shadow': offset + 'px ' + offset + 'px ' + offset + 'px ' + gaugeGlobals.shadowColour, + 'border-radius': Math.floor(size / 2) + 'px' }; - // ######################################################## - // End of gauges() var declarations - // ######################################################## + }, // - // Execution starts here + // generate a colour gradient based on start and end values // + gradient = function (startCol, endCol, fraction) { + var redOrigin, grnOrigin, bluOrigin, + gradientSizeRed, gradientSizeGrn, gradientSizeBlu; - // test for canvas support before we do anything else, especially reference steelseries which will cause the script to abort! - if (!document.createElement('canvas').getContext) { - // failed, no canvas support detected - $('body').html(strings.canvasnosupport); - setTimeout(function () { - window.location = config.oldGauges; - }, 3000); - return false; - } else { - // - // Called when the document object has loaded - // This starts the whole script. - // - $(document).ready(function () { - // Kick it all off - false for web page, true for dashboard - init(config.dashboardMode); - }); - } + redOrigin = parseInt(startCol.substr(0, 2), 16); + grnOrigin = parseInt(startCol.substr(2, 2), 16); + bluOrigin = parseInt(startCol.substr(4, 2), 16); - return { - setLang : setLang, - setUnits : setUnits, - processData: processData, - config : config, - init : init + gradientSizeRed = parseInt(endCol.substr(0, 2), 16) - redOrigin; // Graduation Size Red + gradientSizeGrn = parseInt(endCol.substr(2, 2), 16) - grnOrigin; + gradientSizeBlu = parseInt(endCol.substr(4, 2), 16) - bluOrigin; + + return (redOrigin + (gradientSizeRed * fraction)).toFixed(0) + ',' + + (grnOrigin + (gradientSizeGrn * fraction)).toFixed(0) + ',' + + (bluOrigin + (gradientSizeBlu * fraction)).toFixed(0); + }, + // + // returns the next highest number in the step sequence + // + nextHighest = function (value, step) { + return +value == 0 ? step : Math.ceil(+value / step) * step; + }, + // + // returns the next lowest number in the step sequence + // + nextLowest = function (value, step) { + return +value == 0 ? -step : Math.floor(+value / step) * step; }; +// ######################################################## +// End of gauges() var declarations +// ######################################################## + +// +// Execution starts here +// + +// test for canvas support before we do anything else, especially reference steelseries which will cause the script to abort! +if (!document.createElement('canvas').getContext) { + // failed, no canvas support detected + $('body').html(strings.canvasnosupport); + setTimeout(function () { + window.location = config.oldGauges; + }, 3000); + return false; +} else { + // + // Called when the document object has loaded + // This starts the whole script. + // + $(document).ready(function () { + // Kick it all off - false for web page, true for dashboard + init(config.dashboardMode); + }); +} + +return { + setLang: setLang, + setUnits: setUnits, + processData: processData, + config: config, + init: init +}; }()); // =============================================================================================================================== // =============================================================================================================================== // =============================================================================================================================== - /*! - * Image w/ description tooltip v2.0 - For FF1+ IE6+ Opr8+ - * Created: April 23rd, 2010. This notice must stay intact for usage - * Author: Dynamic Drive at http://www.dynamicdrive.com/ - * Visit http://www.dynamicdrive.com/ for full source code - * Modified: M Crossley June 2011, January 2012 - * v2.- - */ +/*! +* Image w/ description tooltip v2.0 - For FF1+ IE6+ Opr8+ +* Created: April 23rd, 2010. This notice must stay intact for usage +* Author: Dynamic Drive at http://www.dynamicdrive.com/ +* Visit http://www.dynamicdrive.com/ for full source code +* Modified: M Crossley June 2011, January 2012 +* v2.- +*/ var ddimgtooltip; ddimgtooltip = { tiparray: (function () { - var style = {background: '#FFFFFF', color: 'black', border: '2px ridge darkblue'}, + var style = { background: '#FFFFFF', color: 'black', border: '2px ridge darkblue' }, i = 12, // set to number of tooltips required tooltips = []; - for (;i--;) { + for (; i--;) { tooltips[i] = [null, ' ', style]; } return tooltips; @@ -4279,7 +4280,7 @@ ddimgtooltip = { .html( ((tipinfo[1]) ? '
' + tipinfo[1] + '
' : '') + (tipinfo[0] !== null ? '
' : '') + '_img" src="' + tipinfo[0] + '" />
' : '') ) .css(tipinfo[2] || {}) .appendTo(document.body); @@ -4301,11 +4302,11 @@ ddimgtooltip = { // last ditch attempt to keep the graphs 'on page' x = Math.max(x, 0); if (tipw >= wWidth) { - $($tooltip.attr('id') + '_img').css({width: wWidth - 20}); - $('#' + $tooltip.attr('id') + '_img').css({width: wWidth - 20}); + $($tooltip.attr('id') + '_img').css({ width: wWidth - 20 }); + $('#' + $tooltip.attr('id') + '_img').css({ width: wWidth - 20 }); y = e.pageY + 5; } - $tooltip.css({left: x, top: y}); + $tooltip.css({ left: x, top: y }); }, delaybox: function ($, $tooltip) { diff --git a/lib/steelseries/scripts/src/RGraph.rose.js b/lib/steelseries/scripts/src/RGraph.rose.js index 2e2c176..bef134d 100644 --- a/lib/steelseries/scripts/src/RGraph.rose.js +++ b/lib/steelseries/scripts/src/RGraph.rose.js @@ -1,834 +1,824 @@ - /** - * o------------------------------------------------------------------------------o - * | This file is part of the RGraph package - you can learn more at: | - * | | - * | http://www.rgraph.net | - * | | - * | This package is licensed under the RGraph license. For all kinds of business | - * | purposes there is a small one-time licensing fee to pay and for non | - * | commercial purposes it is free to use. You can read the full license here: | - * | | - * | http://www.rgraph.net/LICENSE.txt | - * o------------------------------------------------------------------------------o - */ +/** +* o------------------------------------------------------------------------------o +* | This file is part of the RGraph package - you can learn more at: | +* | | +* | http://www.rgraph.net | +* | | +* | This package is licensed under the RGraph license. For all kinds of business | +* | purposes there is a small one-time licensing fee to pay and for non | +* | commercial purposes it is free to use. You can read the full license here: | +* | | +* | http://www.rgraph.net/LICENSE.txt | +* o------------------------------------------------------------------------------o +*/ + +if (typeof (RGraph) == 'undefined') RGraph = {}; + +/** +* The rose chart constuctor +* +* @param object canvas +* @param array data +*/ +RGraph.Rose = function (id, data) { + this.id = id; + this.canvas = document.getElementById(id); + this.context = this.canvas.getContext('2d'); + this.data = data; + this.canvas.__object__ = this; + this.type = 'rose'; + this.isRGraph = true; + this.uid = RGraph.CreateUID(); + this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID(); + this.colorsParsed = false; - if (typeof(RGraph) == 'undefined') RGraph = {}; /** - * The rose chart constuctor - * - * @param object canvas - * @param array data + * Compatibility with older browsers */ - RGraph.Rose = function (id, data) - { - this.id = id; - this.canvas = document.getElementById(id); - this.context = this.canvas.getContext('2d'); - this.data = data; - this.canvas.__object__ = this; - this.type = 'rose'; - this.isRGraph = true; - this.uid = RGraph.CreateUID(); - this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID(); - this.colorsParsed = false; + RGraph.OldBrowserCompat(this.context); - /** - * Compatibility with older browsers - */ - RGraph.OldBrowserCompat(this.context); + this.centerx = 0; + this.centery = 0; + this.radius = 0; + this.max = 0; + this.angles = []; - - this.centerx = 0; - this.centery = 0; - this.radius = 0; - this.max = 0; - this.angles = []; - - this.properties = { - 'chart.background.axes': true, - 'chart.background.axes.color': 'black', - 'chart.background.grid': true, - 'chart.background.grid.color': '#ccc', - 'chart.background.grid.size': null, - 'chart.background.grid.spokes': null, - 'chart.background.grid.count': 5, - 'chart.centerx': null, - 'chart.centery': null, - 'chart.radius': null, - 'chart.colors': ['rgba(255,0,0,0.5)', 'rgba(255,255,0,0.5)', 'rgba(0,255,255,0.5)', 'rgb(0,255,0)', 'gray', 'blue', 'rgb(255,128,255)','green', 'pink', 'gray', 'aqua'], - 'chart.colors.sequential': false, - 'chart.colors.alpha': null, - 'chart.margin': 0, - 'chart.strokestyle': '#aaa', - 'chart.gutter.left': 25, - 'chart.gutter.right': 25, - 'chart.gutter.top': 25, - 'chart.gutter.bottom': 25, - 'chart.title': '', - 'chart.title.background': null, - 'chart.title.hpos': null, - 'chart.title.vpos': null, - 'chart.title.bold': true, - 'chart.title.font': null, - 'chart.title.x': null, - 'chart.title.y': null, - 'chart.title.halign': null, - 'chart.title.valign': null, - 'chart.labels': null, - 'chart.labels.position': 'center', - 'chart.labels.axes': 'nsew', - 'chart.labels.offset': 0, - 'chart.text.color': 'black', - 'chart.text.font': 'Arial', - 'chart.text.size': 10, - 'chart.key': null, - 'chart.key.background': 'white', - 'chart.key.position': 'graph', - 'chart.key.halign': 'right', - 'chart.key.shadow': false, - 'chart.key.shadow.color': '#666', - 'chart.key.shadow.blur': 3, - 'chart.key.shadow.offsetx': 2, - 'chart.key.shadow.offsety': 2, - 'chart.key.position.gutter.boxed': true, - 'chart.key.position.x': null, - 'chart.key.position.y': null, - 'chart.key.color.shape': 'square', - 'chart.key.rounded': true, - 'chart.key.linewidth': 1, - 'chart.key.colors': null, - 'chart.contextmenu': null, - 'chart.tooltips': null, - 'chart.tooltips.event': 'onclick', - 'chart.tooltips.effect': 'fade', - 'chart.tooltips.css.class': 'RGraph_tooltip', - 'chart.tooltips.highlight': true, - 'chart.highlight.stroke': 'rgba(0,0,0,0)', - 'chart.highlight.fill': 'rgba(255,255,255,0.7)', - 'chart.annotatable': false, - 'chart.annotate.color': 'black', - 'chart.zoom.factor': 1.5, - 'chart.zoom.fade.in': true, - 'chart.zoom.fade.out': true, - 'chart.zoom.hdir': 'right', - 'chart.zoom.vdir': 'down', - 'chart.zoom.frames': 25, - 'chart.zoom.delay': 16.666, - 'chart.zoom.shadow': true, - 'chart.zoom.background': true, - 'chart.zoom.action': 'zoom', - 'chart.resizable': false, - 'chart.resize.handle.adjust': [0,0], - 'chart.resize.handle.background': null, - 'chart.adjustable': false, - 'chart.ymax': null, - 'chart.ymin': 0, - 'chart.scale.decimals': null, - 'chart.scale.point': '.', - 'chart.scale.thousand': ',', - 'chart.variant': 'stacked', - 'chart.exploded': 0, - 'chart.events.mousemove': null, - 'chart.events.click': null, - 'chart.animation.roundrobin.factor': 1, - 'chart.animation.roundrobin.radius': true, - 'chart.animation.grow.multiplier': 1 - } + this.properties = { + 'chart.background.axes': true, + 'chart.background.axes.color': 'black', + 'chart.background.grid': true, + 'chart.background.grid.color': '#ccc', + 'chart.background.grid.size': null, + 'chart.background.grid.spokes': null, + 'chart.background.grid.count': 5, + 'chart.centerx': null, + 'chart.centery': null, + 'chart.radius': null, + 'chart.colors': ['rgba(255,0,0,0.5)', 'rgba(255,255,0,0.5)', 'rgba(0,255,255,0.5)', 'rgb(0,255,0)', 'gray', 'blue', 'rgb(255,128,255)', 'green', 'pink', 'gray', 'aqua'], + 'chart.colors.sequential': false, + 'chart.colors.alpha': null, + 'chart.margin': 0, + 'chart.strokestyle': '#aaa', + 'chart.gutter.left': 25, + 'chart.gutter.right': 25, + 'chart.gutter.top': 25, + 'chart.gutter.bottom': 25, + 'chart.title': '', + 'chart.title.background': null, + 'chart.title.hpos': null, + 'chart.title.vpos': null, + 'chart.title.bold': true, + 'chart.title.font': null, + 'chart.title.x': null, + 'chart.title.y': null, + 'chart.title.halign': null, + 'chart.title.valign': null, + 'chart.labels': null, + 'chart.labels.position': 'center', + 'chart.labels.axes': 'nsew', + 'chart.labels.offset': 0, + 'chart.text.color': 'black', + 'chart.text.font': 'Arial', + 'chart.text.size': 10, + 'chart.key': null, + 'chart.key.background': 'white', + 'chart.key.position': 'graph', + 'chart.key.halign': 'right', + 'chart.key.shadow': false, + 'chart.key.shadow.color': '#666', + 'chart.key.shadow.blur': 3, + 'chart.key.shadow.offsetx': 2, + 'chart.key.shadow.offsety': 2, + 'chart.key.position.gutter.boxed': true, + 'chart.key.position.x': null, + 'chart.key.position.y': null, + 'chart.key.color.shape': 'square', + 'chart.key.rounded': true, + 'chart.key.linewidth': 1, + 'chart.key.colors': null, + 'chart.contextmenu': null, + 'chart.tooltips': null, + 'chart.tooltips.event': 'onclick', + 'chart.tooltips.effect': 'fade', + 'chart.tooltips.css.class': 'RGraph_tooltip', + 'chart.tooltips.highlight': true, + 'chart.highlight.stroke': 'rgba(0,0,0,0)', + 'chart.highlight.fill': 'rgba(255,255,255,0.7)', + 'chart.annotatable': false, + 'chart.annotate.color': 'black', + 'chart.zoom.factor': 1.5, + 'chart.zoom.fade.in': true, + 'chart.zoom.fade.out': true, + 'chart.zoom.hdir': 'right', + 'chart.zoom.vdir': 'down', + 'chart.zoom.frames': 25, + 'chart.zoom.delay': 16.666, + 'chart.zoom.shadow': true, + 'chart.zoom.background': true, + 'chart.zoom.action': 'zoom', + 'chart.resizable': false, + 'chart.resize.handle.adjust': [0, 0], + 'chart.resize.handle.background': null, + 'chart.adjustable': false, + 'chart.ymax': null, + 'chart.ymin': 0, + 'chart.scale.decimals': null, + 'chart.scale.point': '.', + 'chart.scale.thousand': ',', + 'chart.variant': 'stacked', + 'chart.exploded': 0, + 'chart.events.mousemove': null, + 'chart.events.click': null, + 'chart.animation.roundrobin.factor': 1, + 'chart.animation.roundrobin.radius': true, + 'chart.animation.grow.multiplier': 1 + } - /** - * Create the $ objects. In the case of non-equi-angular rose charts it actually creates too many $ objects, - * but it doesn't matter. - */ - var linear_data = RGraph.array_linearize(this.data); - for (var i=0; i 0 && this.Get('chart.key').length >= 3) { + this.centerx = this.centerx - this.Get('chart.gutter.right') + 5; + } + + + + // User specified radius, centerx and centery + if (typeof (this.Get('chart.centerx')) == 'number') this.centerx = this.Get('chart.centerx'); + if (typeof (this.Get('chart.centery')) == 'number') this.centery = this.Get('chart.centery'); + if (typeof (this.Get('chart.radius')) == 'number') this.radius = this.Get('chart.radius'); + + /** + * Parse the colors for gradients. Its down here so that the center X/Y can be used + */ + if (!this.colorsParsed) { + + this.parseColors(); + + // Don't want to do this again + this.colorsParsed = true; + } + + this.DrawBackground(); + this.DrawRose(); + this.DrawLabels(); + + /** + * Setup the context menu if required + */ + if (this.Get('chart.contextmenu')) { + RGraph.ShowContext(this); } /** - * A simple getter - * - * @param string name The name of the property to get + * This function enables resizing */ - RGraph.Rose.prototype.Get = function (name) - { - /** - * This should be done first - prepend the property name with "chart." if necessary - */ - if (name.substr(0,6) != 'chart.') { - name = 'chart.' + name; - } - - return this.properties[name.toLowerCase()]; + if (this.Get('chart.resizable')) { + RGraph.AllowResizing(this); } /** - * This method draws the rose chart + * This function enables adjusting */ - RGraph.Rose.prototype.Draw = function () - { - /** - * Fire the onbeforedraw event - */ - RGraph.FireCustomEvent(this, 'onbeforedraw'); - - - - /** - * This doesn't affect the chart, but is used for compatibility - */ - this.gutterLeft = this.Get('chart.gutter.left'); - this.gutterRight = this.Get('chart.gutter.right'); - this.gutterTop = this.Get('chart.gutter.top'); - this.gutterBottom = this.Get('chart.gutter.bottom'); - - // Calculate the radius - this.radius = (Math.min(this.canvas.width - this.gutterLeft - this.gutterRight, this.canvas.height - this.gutterTop - this.gutterBottom) / 2); - this.centerx = ((this.canvas.width - this.gutterLeft - this.gutterRight) / 2) + this.gutterLeft; - this.centery = ((this.canvas.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop; - this.angles = []; - this.total = 0; - this.startRadians = 0; - - /** - * Change the centerx marginally if the key is defined - */ - if (this.Get('chart.key') && this.Get('chart.key').length > 0 && this.Get('chart.key').length >= 3) { - this.centerx = this.centerx - this.Get('chart.gutter.right') + 5; - } - - - - // User specified radius, centerx and centery - if (typeof(this.Get('chart.centerx')) == 'number') this.centerx = this.Get('chart.centerx'); - if (typeof(this.Get('chart.centery')) == 'number') this.centery = this.Get('chart.centery'); - if (typeof(this.Get('chart.radius')) == 'number') this.radius = this.Get('chart.radius'); - - /** - * Parse the colors for gradients. Its down here so that the center X/Y can be used - */ - if (!this.colorsParsed) { - - this.parseColors(); - - // Don't want to do this again - this.colorsParsed = true; - } - - this.DrawBackground(); - this.DrawRose(); - this.DrawLabels(); - - /** - * Setup the context menu if required - */ - if (this.Get('chart.contextmenu')) { - RGraph.ShowContext(this); - } - - - /** - * This function enables resizing - */ - if (this.Get('chart.resizable')) { - RGraph.AllowResizing(this); - } - - - /** - * This function enables adjusting - */ - if (this.Get('chart.adjustable')) { - RGraph.AllowAdjusting(this); - } - - - /** - * This installs the event listeners - */ - RGraph.InstallEventListeners(this); - - - /** - * Fire the RGraph ondraw event - */ - RGraph.FireCustomEvent(this, 'ondraw'); + if (this.Get('chart.adjustable')) { + RGraph.AllowAdjusting(this); } + /** - * This method draws the rose charts background + * This installs the event listeners */ - RGraph.Rose.prototype.DrawBackground = function () - { - this.context.lineWidth = 1; + RGraph.InstallEventListeners(this); + + + /** + * Fire the RGraph ondraw event + */ + RGraph.FireCustomEvent(this, 'ondraw'); +} + +/** +* This method draws the rose charts background +*/ +RGraph.Rose.prototype.DrawBackground = function () { + this.context.lineWidth = 1; - // Draw the background grey circles/spokes - if (this.properties['chart.background.grid']) { - if (typeof(this.properties['chart.background.grid.count']) == 'number') { - this.properties['chart.background.grid.size'] = this.radius / this.properties['chart.background.grid.count']; - } + // Draw the background grey circles/spokes + if (this.properties['chart.background.grid']) { + if (typeof (this.properties['chart.background.grid.count']) == 'number') { + this.properties['chart.background.grid.size'] = this.radius / this.properties['chart.background.grid.count']; + } - this.context.beginPath(); - this.context.strokeStyle = this.properties['chart.background.grid.color']; + this.context.beginPath(); + this.context.strokeStyle = this.properties['chart.background.grid.color']; + + // Radius must be greater than 0 for Opera to work + for (var i = this.properties['chart.background.grid.size']; i <= this.radius; i += this.properties['chart.background.grid.size']) { + + //this.context.moveTo(this.centerx + i, this.centery); + + // Radius must be greater than 0 for Opera to work + this.context.arc(this.centerx, + this.centery, + i, + 0, + TWOPI, + false); + } + this.context.stroke(); + + + + + + + // Draw the background lines that go from the center outwards + this.context.beginPath(); + if (typeof (this.properties['chart.background.grid.spokes']) == 'number') { + + var num = (360 / this.properties['chart.background.grid.spokes']); + + for (var i = num; i <= 360; i += num) { // Radius must be greater than 0 for Opera to work - for (var i=this.properties['chart.background.grid.size']; i<=this.radius; i+=this.properties['chart.background.grid.size']) { + this.context.arc(this.centerx, + this.centery, + this.radius, + (i / (180 / PI)) - HALFPI, + ((i + 0.0001) / (180 / PI)) - HALFPI, + 0); - //this.context.moveTo(this.centerx + i, this.centery); - - // Radius must be greater than 0 for Opera to work - this.context.arc(this.centerx, - this.centery, - i, - 0, - TWOPI, - false); - } - this.context.stroke(); - - - - - - - // Draw the background lines that go from the center outwards - this.context.beginPath(); - if (typeof(this.properties['chart.background.grid.spokes']) == 'number') { - - var num = (360 / this.properties['chart.background.grid.spokes']); - - for (var i=num; i<=360; i+=num) { - - // Radius must be greater than 0 for Opera to work - this.context.arc(this.centerx, - this.centery, - this.radius, - (i / (180 / PI)) - HALFPI, - ((i + 0.0001) / (180 / PI)) - HALFPI, - 0); - - this.context.lineTo(this.centerx, this.centery); - } - } else { - for (var i=15; i<=360; i+=15) { - - // Radius must be greater than 0 for Opera to work - this.context.arc(this.centerx, - this.centery, - this.radius, - (i / (180/ PI)) - HALFPI, - ((i + 0.0001) / (180/ PI)) - HALFPI, - false); - - this.context.lineTo(this.centerx, this.centery); - } - } - this.context.stroke(); - } - - - - if (this.Get('chart.background.axes')) { - this.context.beginPath(); - this.context.strokeStyle = this.Get('chart.background.axes.color'); - - // Draw the X axis - this.context.moveTo(this.centerx - this.radius, Math.round(this.centery) ); - this.context.lineTo(this.centerx + this.radius, Math.round(this.centery) ); - - // Draw the X ends - this.context.moveTo(Math.round(this.centerx - this.radius), this.centery - 5); - this.context.lineTo(Math.round(this.centerx - this.radius), this.centery + 5); - this.context.moveTo(Math.round(this.centerx + this.radius), this.centery - 5); - this.context.lineTo(Math.round(this.centerx + this.radius), this.centery + 5); - - // Draw the X check marks - for (var i=(this.centerx - this.radius); i<(this.centerx + this.radius); i+=(this.radius / 5)) { - this.context.moveTo(Math.round(i), this.centery - 3); - this.context.lineTo(Math.round(i), this.centery + 3.5); + this.context.lineTo(this.centerx, this.centery); } + } else { + for (var i = 15; i <= 360; i += 15) { - // Draw the Y check marks - for (var i=(this.centery - this.radius); i<(this.centery + this.radius); i+=(this.radius / 5)) { - this.context.moveTo(this.centerx - 3, Math.round(i)); - this.context.lineTo(this.centerx + 3, Math.round(i)); + // Radius must be greater than 0 for Opera to work + this.context.arc(this.centerx, + this.centery, + this.radius, + (i / (180 / PI)) - HALFPI, + ((i + 0.0001) / (180 / PI)) - HALFPI, + false); + + this.context.lineTo(this.centerx, this.centery); } - - // Draw the Y axis - this.context.moveTo(Math.round(this.centerx), this.centery - this.radius); - this.context.lineTo(Math.round(this.centerx), this.centery + this.radius); - - // Draw the Y ends - this.context.moveTo(this.centerx - 5, Math.round(this.centery - this.radius)); - this.context.lineTo(this.centerx + 5, Math.round(this.centery - this.radius)); - - this.context.moveTo(this.centerx - 5, Math.round(this.centery + this.radius)); - this.context.lineTo(this.centerx + 5, Math.round(this.centery + this.radius)); - - // Stroke it - this.context.closePath(); - this.context.stroke(); } + this.context.stroke(); } - /** - * This method draws the data on the graph - */ - RGraph.Rose.prototype.DrawRose = function () - { - var max = 0; - var data = this.data; - var margin = RGraph.degrees2Radians(this.Get('chart.margin')); + if (this.Get('chart.background.axes')) { + this.context.beginPath(); + this.context.strokeStyle = this.Get('chart.background.axes.color'); - // Must be at least two data points - //if (data.length < 2) { - // alert('[ROSE] Must be at least two data points! [' + data + ']'); - // return; - //} + // Draw the X axis + this.context.moveTo(this.centerx - this.radius, Math.round(this.centery)); + this.context.lineTo(this.centerx + this.radius, Math.round(this.centery)); - // Work out the maximum value and the sum - if (!this.Get('chart.ymax')) { - // Work out the max - for (var i=0; i -1) { - RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.2), RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.4), RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.6), RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.8), RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery - r, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - } + var r = this.radius; + var font_face = this.Get('chart.text.font'); + var font_size = this.Get('chart.text.size'); + var context = this.context; + var axes = this.Get('chart.labels.axes').toLowerCase(); + var decimals = this.Get('chart.scale.decimals'); + var units_pre = this.Get('chart.units.pre'); + var units_post = this.Get('chart.units.post'); - // The "South" axis labels - if (axes.indexOf('s') > -1) { - RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.2), RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.4), RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.6), RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.8), RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx, this.centery + r, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - } - - // The "East" axis labels - if (axes.indexOf('e') > -1) { - RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.2), this.centery, RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.4), this.centery, RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.6), this.centery, RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.8), this.centery, RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx + r, this.centery, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - } - - // The "West" axis labels - if (axes.indexOf('w') > -1) { - RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.2), this.centery, RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.4), this.centery, RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.6), this.centery, RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.8), this.centery, RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - RGraph.Text(context, font_face, font_size, this.centerx - r, this.centery, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); - } - - if (axes.length > 0) { - RGraph.Text(context, font_face, font_size, this.centerx, this.centery, typeof(this.Get('chart.ymin')) == 'number' ? RGraph.number_format(this, Number(this.Get('chart.ymin')).toFixed(this.Get('chart.scale.decimals')), units_pre, units_post) : '0', 'center', 'center', true, false, color); - } + // Draw any circular labels + if (typeof (this.Get('chart.labels')) == 'object' && this.Get('chart.labels')) { + this.DrawCircularLabels(context, this.Get('chart.labels'), font_face, font_size, r + 10); } - /** - * Draws the circular labels that go around the charts - * - * @param labels array The labels that go around the chart - */ - RGraph.Rose.prototype.DrawCircularLabels = function (context, labels, font_face, font_size, r) - { - var variant = this.Get('chart.variant'); - var position = this.Get('chart.labels.position'); - var r = r + 5 + this.Get('chart.labels.offset'); - - for (var i=0; i this.centerx) { - halign = 'left'; - } else if (x == this.centerx) { - halign = 'center'; - } else { - halign = 'right'; - } - - RGraph.Text(context, font_face, font_size, x, y, String(labels[i]), 'center', halign); - } + // Size can be specified seperately for the scale now + if (typeof (this.properties['chart.text.size.scale']) == 'number') { + font_size = this.properties['chart.text.size.scale']; } + var color = 'rgba(255,255,255,0.8)'; + + // The "North" axis labels + if (axes.indexOf('n') > -1) { + RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.2), RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.4), RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.6), RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery - (r * 0.8), RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery - r, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + } + + // The "South" axis labels + if (axes.indexOf('s') > -1) { + RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.2), RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.4), RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.6), RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery + (r * 0.8), RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx, this.centery + r, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + } + + // The "East" axis labels + if (axes.indexOf('e') > -1) { + RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.2), this.centery, RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.4), this.centery, RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.6), this.centery, RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx + (r * 0.8), this.centery, RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx + r, this.centery, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + } + + // The "West" axis labels + if (axes.indexOf('w') > -1) { + RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.2), this.centery, RGraph.number_format(this, Number(this.scale[0]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.4), this.centery, RGraph.number_format(this, Number(this.scale[1]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.6), this.centery, RGraph.number_format(this, Number(this.scale[2]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx - (r * 0.8), this.centery, RGraph.number_format(this, Number(this.scale[3]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + RGraph.Text(context, font_face, font_size, this.centerx - r, this.centery, RGraph.number_format(this, Number(this.scale[4]).toFixed(decimals), units_pre, units_post), 'center', 'center', true, false, color); + } + + if (axes.length > 0) { + RGraph.Text(context, font_face, font_size, this.centerx, this.centery, typeof (this.Get('chart.ymin')) == 'number' ? RGraph.number_format(this, Number(this.Get('chart.ymin')).toFixed(this.Get('chart.scale.decimals')), units_pre, units_post) : '0', 'center', 'center', true, false, color); + } +} + + +/** +* Draws the circular labels that go around the charts +* +* @param labels array The labels that go around the chart +*/ +RGraph.Rose.prototype.DrawCircularLabels = function (context, labels, font_face, font_size, r) { + var variant = this.Get('chart.variant'); + var position = this.Get('chart.labels.position'); + var r = r + 5 + this.Get('chart.labels.offset'); + + for (var i = 0; i < this.angles.length; ++i) { + if (typeof (variant) == 'string' && variant == 'non-equi-angular') { + var a = Number(this.angles[i][0]) + ((this.angles[i][1] - this.angles[i][0]) / 2); + } else { + var a = (TWOPI / labels.length) * (i + 1) - (TWOPI / (labels.length * 2)); + var a = a - HALFPI + (this.Get('chart.labels.position') == 'edge' ? ((TWOPI / labels.length) / 2) : 0); + } + + var x = this.centerx + (Math.cos(a) * r); + var y = this.centery + (Math.sin(a) * r); + + // Horizontal alignment + if (x > this.centerx) { + halign = 'left'; + } else if (x == this.centerx) { + halign = 'center'; + } else { + halign = 'right'; + } + + RGraph.Text(context, font_face, font_size, x, y, String(labels[i]), 'center', halign); + } +} @@ -853,45 +843,46 @@ - /** - * This function is for use with circular graph types, eg the Pie or Rose. Pass it your event object - * and it will pass you back the corresponding segment details as an array: - * - * [x, y, r, startAngle, endAngle] - * - * Angles are measured in degrees, and are measured from the "east" axis (just like the canvas). - * - * @param object e Your event object - */ - RGraph.Rose.prototype.getShape = - RGraph.Rose.prototype.getSegment = function (e) - { + + +/** +* This function is for use with circular graph types, eg the Pie or Rose. Pass it your event object +* and it will pass you back the corresponding segment details as an array: +* +* [x, y, r, startAngle, endAngle] +* +* Angles are measured in degrees, and are measured from the "east" axis (just like the canvas). +* +* @param object e Your event object +*/ +RGraph.Rose.prototype.getShape = + RGraph.Rose.prototype.getSegment = function (e) { RGraph.FixEventObject(e); - var canvas = this.canvas; + var canvas = this.canvas; var context = this.context; - var angles = this.angles; - var ret = []; + var angles = this.angles; + var ret = []; /** * Go through all of the angles checking each one */ - for (var i=0; i 0) { + this.context.arc(shape['x'], shape['y'], shape['radius.start'], shape['angle.end'], shape['angle.start'], true); } else { - explodedx = 0; - explodedy = 0; + this.context.lineTo(shape['x'], shape['y']); } + this.context.closePath(); - return [explodedx, explodedy]; + this.context.stroke(); + this.context.fill(); } +} - /** - * This function facilitates the installation of tooltip event listeners if - * tooltips are defined. - */ - RGraph.Rose.prototype.AllowTooltips = function () - { - // Preload any tooltip images that are used in the tooltips - RGraph.PreLoadTooltipImages(this); +/** +* The getObjectByXY() worker method. Don't call this call: +* +* RGraph.ObjectRegistry.getObjectByXY(e) +* +* @param object e The event object +*/ +RGraph.Rose.prototype.getObjectByXY = function (e) { + var mouseXY = RGraph.getMouseXY(e); + // Work out the radius + var radius = RGraph.getHypLength(this.centerx, this.centery, mouseXY[0], mouseXY[1]); - /** - * This installs the window mousedown event listener that lears any - * highlight that may be visible. - */ - RGraph.InstallWindowMousedownTooltipListener(this); + if ( + mouseXY[0] > (this.centerx - this.radius) + && mouseXY[0] < (this.centerx + this.radius) + && mouseXY[1] > (this.centery - this.radius) + && mouseXY[1] < (this.centery + this.radius) + && radius <= this.radius + ) { - - /** - * This installs the canvas mousemove event listener. This function - * controls the pointer shape. - */ - RGraph.InstallCanvasMousemoveTooltipListener(this); - - - /** - * This installs the canvas mouseup event listener. This is the - * function that actually shows the appropriate tooltip (if any). - */ - RGraph.InstallCanvasMouseupTooltipListener(this); + return this; } +} - /** - * Each object type has its own Highlight() function which highlights the appropriate shape - * - * @param object shape The shape to highlight - */ - RGraph.Rose.prototype.Highlight = function (shape) - { - if (this.Get('chart.tooltips.highlight')) { - // Add the new segment highlight - this.context.beginPath(); +/** +* This function positions a tooltip when it is displayed +* +* @param obj object The chart object +* @param int x The X coordinate specified for the tooltip +* @param int y The Y coordinate specified for the tooltip +* @param objec tooltip The tooltips DIV element +*/ +RGraph.Rose.prototype.positionTooltip = function (obj, x, y, tooltip, idx) { - this.context.strokeStyle = this.Get('chart.highlight.stroke'); - this.context.fillStyle = this.Get('chart.highlight.fill'); + var coordX = obj.angles[idx][4]; + var coordY = obj.angles[idx][5]; + var angleStart = obj.angles[idx][0]; + var angleEnd = obj.angles[idx][1]; + var radius = ((obj.angles[idx][3] - obj.angles[idx][2]) / 2) + obj.angles[idx][2]; - this.context.arc(shape['x'], shape['y'], shape['radius.end'], shape['angle.start'], shape['angle.end'], false); - - if (shape['radius.start'] > 0) { - this.context.arc(shape['x'], shape['y'], shape['radius.start'], shape['angle.end'], shape['angle.start'], true); - } else { - this.context.lineTo(shape['x'], shape['y']); - } - this.context.closePath(); - - this.context.stroke(); - this.context.fill(); - } - } + var angleCenter = ((angleEnd - angleStart) / 2) + angleStart; + var canvasXY = RGraph.getCanvasXY(obj.canvas); + var gutterLeft = obj.Get('chart.gutter.left'); + var gutterTop = obj.Get('chart.gutter.top'); + var width = tooltip.offsetWidth; + var height = tooltip.offsetHeight; + // By default any overflow is hidden + tooltip.style.overflow = ''; - /** - * The getObjectByXY() worker method. Don't call this call: - * - * RGraph.ObjectRegistry.getObjectByXY(e) - * - * @param object e The event object - */ - RGraph.Rose.prototype.getObjectByXY = function (e) - { - var mouseXY = RGraph.getMouseXY(e); + // The arrow + var img = new Image(); + img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC'; + img.style.position = 'absolute'; + img.id = '__rgraph_tooltip_pointer__'; + img.style.top = (tooltip.offsetHeight - 2) + 'px'; + tooltip.appendChild(img); - // Work out the radius - var radius = RGraph.getHypLength(this.centerx, this.centery, mouseXY[0], mouseXY[1]); + // Reposition the tooltip if at the edges: - if ( - mouseXY[0] > (this.centerx - this.radius) - && mouseXY[0] < (this.centerx + this.radius) - && mouseXY[1] > (this.centery - this.radius) - && mouseXY[1] < (this.centery + this.radius) - && radius <= this.radius - ) { - - return this; - } - } - - - - /** - * This function positions a tooltip when it is displayed - * - * @param obj object The chart object - * @param int x The X coordinate specified for the tooltip - * @param int y The Y coordinate specified for the tooltip - * @param objec tooltip The tooltips DIV element - */ - RGraph.Rose.prototype.positionTooltip = function (obj, x, y, tooltip, idx) - { - - var coordX = obj.angles[idx][4]; - var coordY = obj.angles[idx][5]; - var angleStart = obj.angles[idx][0]; - var angleEnd = obj.angles[idx][1]; - var radius = ((obj.angles[idx][3] - obj.angles[idx][2]) / 2) + obj.angles[idx][2]; - - var angleCenter = ((angleEnd - angleStart) / 2) + angleStart; - var canvasXY = RGraph.getCanvasXY(obj.canvas); - var gutterLeft = obj.Get('chart.gutter.left'); - var gutterTop = obj.Get('chart.gutter.top'); - var width = tooltip.offsetWidth; - var height = tooltip.offsetHeight; - - - // By default any overflow is hidden - tooltip.style.overflow = ''; - - // The arrow - var img = new Image(); - img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC'; - img.style.position = 'absolute'; - img.id = '__rgraph_tooltip_pointer__'; - img.style.top = (tooltip.offsetHeight - 2) + 'px'; - tooltip.appendChild(img); - - // Reposition the tooltip if at the edges: - - // LEFT edge - if ((canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) - (width / 2)) < 10) { - tooltip.style.left = (canvasXY[0] + coordX + (Math.cos(angleCenter) * radius)- (width * 0.1)) + 'px'; - tooltip.style.top = (canvasXY[1] + coordY + (Math.sin(angleCenter) * radius)- height - 5) + 'px'; - img.style.left = ((width * 0.1) - 8.5) + 'px'; + // LEFT edge + if ((canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) - (width / 2)) < 10) { + tooltip.style.left = (canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) - (width * 0.1)) + 'px'; + tooltip.style.top = (canvasXY[1] + coordY + (Math.sin(angleCenter) * radius) - height - 5) + 'px'; + img.style.left = ((width * 0.1) - 8.5) + 'px'; // RIGHT edge - } else if ((canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) + (width / 2)) > (document.body.offsetWidth - 10) ) { - tooltip.style.left = (canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) - (width * 0.9)) + 'px'; - tooltip.style.top = (canvasXY[1] + coordY + (Math.sin(angleCenter) * radius)- height - 5) + 'px'; - img.style.left = ((width * 0.9) - 8.5) + 'px'; + } else if ((canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) + (width / 2)) > (document.body.offsetWidth - 10)) { + tooltip.style.left = (canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) - (width * 0.9)) + 'px'; + tooltip.style.top = (canvasXY[1] + coordY + (Math.sin(angleCenter) * radius) - height - 5) + 'px'; + img.style.left = ((width * 0.9) - 8.5) + 'px'; // Default positioning - CENTERED - } else { - tooltip.style.left = (canvasXY[0] + coordX + (Math.cos(angleCenter) * radius)- (width / 2)) + 'px'; - tooltip.style.top = (canvasXY[1] + coordY + (Math.sin(angleCenter) * radius)- height - 5) + 'px'; - img.style.left = ((width * 0.5) - 8.5) + 'px'; - } + } else { + tooltip.style.left = (canvasXY[0] + coordX + (Math.cos(angleCenter) * radius) - (width / 2)) + 'px'; + tooltip.style.top = (canvasXY[1] + coordY + (Math.sin(angleCenter) * radius) - height - 5) + 'px'; + img.style.left = ((width * 0.5) - 8.5) + 'px'; + } +} + + + +/** +* This method gives you the relevant radius for a particular value +* +* @param number value The relevant value to get the radius for +*/ +RGraph.Rose.prototype.getRadius = function (value) { + // Range checking (the Rose minimum is always 0) + if (value < 0 || value > this.max) { + return null; } + var r = (value / this.max) * this.radius; + return r; +} + + + +/** +* This allows for easy specification of gradients +*/ +RGraph.Rose.prototype.parseColors = function () { + for (var i = 0; i < this.properties['chart.colors'].length; ++i) { + this.properties['chart.colors'][i] = this.parseSingleColorForGradient(this.properties['chart.colors'][i]); + } /** - * This method gives you the relevant radius for a particular value - * - * @param number value The relevant value to get the radius for + * Key colors */ - RGraph.Rose.prototype.getRadius = function (value) - { - // Range checking (the Rose minimum is always 0) - if (value < 0 || value > this.max) { - return null; + if (!RGraph.is_null(this.properties['chart.key.colors'])) { + for (var i = 0; i < this.properties['chart.key.colors'].length; ++i) { + this.properties['chart.key.colors'][i] = this.parseSingleColorForGradient(this.properties['chart.key.colors'][i]); } - - var r = (value / this.max) * this.radius; - - return r; } + this.properties['chart.text.color'] = this.parseSingleColorForGradient(this.properties['chart.text.color']); + this.properties['chart.title.color'] = this.parseSingleColorForGradient(this.properties['chart.title.color']); + this.properties['chart.highlight.fill'] = this.parseSingleColorForGradient(this.properties['chart.highlight.fill']); + this.properties['chart.highlight.stroke'] = this.parseSingleColorForGradient(this.properties['chart.highlight.stroke']); +} - /** - * This allows for easy specification of gradients - */ - RGraph.Rose.prototype.parseColors = function () - { - for (var i=0; i threshold && ledBlinking && !thresholdRising)) { + (value > threshold && ledBlinking && !thresholdRising)) { ledBlinking = false; blink(ledBlinking); if (playAlarm) { @@ -898,7 +898,7 @@ var steelseries = (function () { audioElement.play(); } } else if ((value < threshold && ledBlinking && thresholdRising) || - (value > threshold && ledBlinking && !thresholdRising)) { + (value > threshold && ledBlinking && !thresholdRising)) { ledBlinking = false; blink(ledBlinking); if (playAlarm) { @@ -919,7 +919,7 @@ var steelseries = (function () { }; // do we have a callback function to process? - if (callback && typeof(callback) === "function") { + if (callback && typeof (callback) === "function") { tween.onMotionFinished = callback; } @@ -969,26 +969,30 @@ var steelseries = (function () { this.setTitleString = function (title) { titleString = title; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setUnitString = function (unit) { unitString = unit; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setMinValue = function (value) { minValue = parseFloat(value); - resetBuffers({frame: true, - background: true}); - init({frame: true, - background: true}); + resetBuffers({ + frame: true, + background: true + }); + init({ + frame: true, + background: true + }); this.repaint(); return this; }; @@ -999,10 +1003,14 @@ var steelseries = (function () { this.setMaxValue = function (value) { maxValue = parseFloat(value); - resetBuffers({frame: true, - background: true}); - init({frame: true, - background: true}); + resetBuffers({ + frame: true, + background: true + }); + init({ + frame: true, + background: true + }); this.repaint(); return this; }; @@ -1015,30 +1023,36 @@ var steelseries = (function () { newValue = parseFloat(newValue); var targetValue = newValue < minValue ? minValue : (newValue > maxValue ? maxValue : newValue); threshold = targetValue; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setArea = function (areaVal) { area = areaVal; - resetBuffers({background: true, - foreground: true}); - init({background: true, - foreground: true - }); + resetBuffers({ + background: true, + foreground: true + }); + init({ + background: true, + foreground: true + }); this.repaint(); return this; }; this.setSection = function (areaSec) { section = areaSec; - resetBuffers({background: true, - foreground: true}); - init({background: true, - foreground: true - }); + resetBuffers({ + background: true, + foreground: true + }); + init({ + background: true, + foreground: true + }); this.repaint(); return this; }; @@ -1065,65 +1079,69 @@ var steelseries = (function () { }; this.setFrameDesign = function (newFrameDesign) { - resetBuffers({frame: true}); + resetBuffers({ frame: true }); frameDesign = newFrameDesign; - init({frame: true}); + init({ frame: true }); this.repaint(); return this; }; this.setBackgroundColor = function (newBackgroundColor) { - resetBuffers({background: true, - pointer: (pointerType.type === 'type2' || pointerType.type === 'type13' ? true : false) // type2 & 13 depend on background - }); + resetBuffers({ + background: true, + pointer: (pointerType.type === 'type2' || pointerType.type === 'type13' ? true : false) // type2 & 13 depend on background + }); backgroundColor = newBackgroundColor; - init({background: true, // type2 & 13 depend on background - pointer: (pointerType.type === 'type2' || pointerType.type === 'type13' ? true : false) - }); + init({ + background: true, // type2 & 13 depend on background + pointer: (pointerType.type === 'type2' || pointerType.type === 'type13' ? true : false) + }); this.repaint(); return this; }; this.setForegroundType = function (newForegroundType) { - resetBuffers({foreground: true}); + resetBuffers({ foreground: true }); foregroundType = newForegroundType; - init({foreground: true}); + init({ foreground: true }); this.repaint(); return this; }; this.setPointerType = function (newPointerType) { - resetBuffers({pointer: true, - foreground: true - }); + resetBuffers({ + pointer: true, + foreground: true + }); pointerType = newPointerType; - init({pointer: true, - foreground: true - }); + init({ + pointer: true, + foreground: true + }); this.repaint(); return this; }; this.setPointerColor = function (newPointerColor) { - resetBuffers({pointer: true}); + resetBuffers({ pointer: true }); pointerColor = newPointerColor; - init({pointer: true}); + init({ pointer: true }); this.repaint(); return this; }; this.setLedColor = function (newLedColor) { - resetBuffers({led: true}); + resetBuffers({ led: true }); ledColor = newLedColor; - init({led: true}); + init({ led: true }); this.repaint(); return this; }; this.setUserLedColor = function (newLedColor) { - resetBuffers({userLed: true}); + resetBuffers({ userLed: true }); userLedColor = newLedColor; - init({userLed: true}); + init({ userLed: true }); this.repaint(); return this; }; @@ -1177,8 +1195,8 @@ var steelseries = (function () { this.setLcdColor = function (newLcdColor) { lcdColor = newLcdColor; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -1197,30 +1215,32 @@ var steelseries = (function () { this.setFractionalScaleDecimals = function (decimals) { fractionalScaleDecimals = parseInt(decimals, 10); - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setLabelNumberFormat = function (format) { labelNumberFormat = format; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.repaint = function () { if (!initialized) { - init({frame: true, - background: true, - led: true, - userLed: true, - pointer: true, - trend: true, - foreground: true, - odo: true}); + init({ + frame: true, + background: true, + led: true, + userLed: true, + pointer: true, + trend: true, + foreground: true, + odo: true + }); } mainCtx.clearRect(0, 0, size, size); @@ -1255,18 +1275,18 @@ var steelseries = (function () { // Draw the trend indicator if (trendVisible) { switch (trendIndicator.state) { - case 'up': - mainCtx.drawImage(trendUpBuffer, trendPosX, trendPosY); - break; - case 'steady': - mainCtx.drawImage(trendSteadyBuffer, trendPosX, trendPosY); - break; - case 'down': - mainCtx.drawImage(trendDownBuffer, trendPosX, trendPosY); - break; - case 'off': - mainCtx.drawImage(trendOffBuffer, trendPosX, trendPosY); - break; + case 'up': + mainCtx.drawImage(trendUpBuffer, trendPosX, trendPosY); + break; + case 'steady': + mainCtx.drawImage(trendSteadyBuffer, trendPosX, trendPosY); + break; + case 'down': + mainCtx.drawImage(trendDownBuffer, trendPosX, trendPosY); + break; + case 'off': + mainCtx.drawImage(trendOffBuffer, trendPosX, trendPosY); + break; } } @@ -1327,7 +1347,7 @@ var steelseries = (function () { minValue = (undefined === parameters.minValue ? 0 : parameters.minValue), maxValue = (undefined === parameters.maxValue ? (minValue + 100) : parameters.maxValue), niceScale = (undefined === parameters.niceScale ? true : parameters.niceScale), - threshold = (undefined === parameters.threshold ? (maxValue - minValue) / 2 + minValue: parameters.threshold), + threshold = (undefined === parameters.threshold ? (maxValue - minValue) / 2 + minValue : parameters.threshold), thresholdRising = (undefined === parameters.thresholdRising ? true : parameters.thresholdRising), section = (undefined === parameters.section ? null : parameters.section), useSectionColors = (undefined === parameters.useSectionColors ? false : parameters.useSectionColors), @@ -1433,47 +1453,47 @@ var steelseries = (function () { var trendPosY = size * 0.57; switch (gaugeType.type) { - case 'type1': - freeAreaAngle = 0; - rotationOffset = PI; - bargraphOffset = 0; - tickmarkOffset = HALF_PI; - angleRange = HALF_PI; - degAngleRange = angleRange * DEG_FACTOR; - angleStep = angleRange / range; - break; + case 'type1': + freeAreaAngle = 0; + rotationOffset = PI; + bargraphOffset = 0; + tickmarkOffset = HALF_PI; + angleRange = HALF_PI; + degAngleRange = angleRange * DEG_FACTOR; + angleStep = angleRange / range; + break; - case 'type2': - freeAreaAngle = 0; - rotationOffset = PI; - bargraphOffset = 0; - tickmarkOffset = HALF_PI; - angleRange = PI; - degAngleRange = angleRange * DEG_FACTOR; - angleStep = angleRange / range; - break; + case 'type2': + freeAreaAngle = 0; + rotationOffset = PI; + bargraphOffset = 0; + tickmarkOffset = HALF_PI; + angleRange = PI; + degAngleRange = angleRange * DEG_FACTOR; + angleStep = angleRange / range; + break; - case 'type3': - freeAreaAngle = 0; - rotationOffset = HALF_PI; - bargraphOffset = -HALF_PI; - tickmarkOffset = 0; - angleRange = 1.5 * PI; - degAngleRange = angleRange * DEG_FACTOR; - angleStep = angleRange / range; - break; + case 'type3': + freeAreaAngle = 0; + rotationOffset = HALF_PI; + bargraphOffset = -HALF_PI; + tickmarkOffset = 0; + angleRange = 1.5 * PI; + degAngleRange = angleRange * DEG_FACTOR; + angleStep = angleRange / range; + break; - case 'type4': - /* falls through */ - default: - freeAreaAngle = 60 * RAD_FACTOR; - rotationOffset = HALF_PI + (freeAreaAngle / 2); - bargraphOffset = -TWO_PI / 6; - tickmarkOffset = 0; - angleRange = TWO_PI - freeAreaAngle; - degAngleRange = angleRange * DEG_FACTOR; - angleStep = angleRange / range; - break; + case 'type4': + /* falls through */ + default: + freeAreaAngle = 60 * RAD_FACTOR; + rotationOffset = HALF_PI + (freeAreaAngle / 2); + bargraphOffset = -TWO_PI / 6; + tickmarkOffset = 0; + angleRange = TWO_PI - freeAreaAngle; + degAngleRange = angleRange * DEG_FACTOR; + angleStep = angleRange / range; + break; } // Buffer for the frame @@ -1556,39 +1576,39 @@ var steelseries = (function () { } switch (gaugeType.type) { - case 'type1': - freeAreaAngle = 0; - rotationOffset = PI; - tickmarkOffset = HALF_PI; - angleRange = HALF_PI; - angleStep = angleRange / range; - break; + case 'type1': + freeAreaAngle = 0; + rotationOffset = PI; + tickmarkOffset = HALF_PI; + angleRange = HALF_PI; + angleStep = angleRange / range; + break; - case 'type2': - freeAreaAngle = 0; - rotationOffset = PI; - tickmarkOffset = HALF_PI; - angleRange = PI; - angleStep = angleRange / range; - break; + case 'type2': + freeAreaAngle = 0; + rotationOffset = PI; + tickmarkOffset = HALF_PI; + angleRange = PI; + angleStep = angleRange / range; + break; - case 'type3': - freeAreaAngle = 0; - rotationOffset = HALF_PI; - tickmarkOffset = 0; - angleRange = 1.5 * PI; - angleStep = angleRange / range; - break; + case 'type3': + freeAreaAngle = 0; + rotationOffset = HALF_PI; + tickmarkOffset = 0; + angleRange = 1.5 * PI; + angleStep = angleRange / range; + break; - case 'type4': // fall through - /* falls through */ - default: - freeAreaAngle = 60 * RAD_FACTOR; - rotationOffset = HALF_PI + (freeAreaAngle / 2); - tickmarkOffset = 0; - angleRange = TWO_PI - freeAreaAngle; - angleStep = angleRange / range; - break; + case 'type4': // fall through + /* falls through */ + default: + freeAreaAngle = 60 * RAD_FACTOR; + rotationOffset = HALF_PI + (freeAreaAngle / 2); + tickmarkOffset = 0; + angleRange = TWO_PI - freeAreaAngle; + angleStep = angleRange / range; + break; } angle = rotationOffset + (value - minValue) * angleStep; }; @@ -1601,7 +1621,7 @@ var steelseries = (function () { var drawBackground = (undefined === parameters.background ? false : parameters.background); var drawLed = (undefined === parameters.led ? false : parameters.led); var drawUserLed = (undefined === parameters.userLed ? false : parameters.userLed); - var drawValue = (undefined === parameters.value ? false : parameters.value); + var drawValue = (undefined === parameters.value ? false : parameters.value); var drawForeground = (undefined === parameters.foreground ? false : parameters.foreground); var drawTrend = (undefined === parameters.trend ? false : parameters.trend); @@ -1647,7 +1667,7 @@ var steelseries = (function () { } // Create tickmarks in background buffer (backgroundBuffer) - if (drawBackground && backgroundVisible) { + if (drawBackground && backgroundVisible) { drawTickmarksImage(backgroundContext, labelNumberFormat); // Create title in background buffer (backgroundBuffer) @@ -1668,9 +1688,11 @@ var steelseries = (function () { sectionAngles = []; do { sectionIndex--; - sectionAngles.push({start: (((section[sectionIndex].start + Math.abs(minValue)) / (maxValue - minValue)) * degAngleRange), - stop: (((section[sectionIndex].stop + Math.abs(minValue)) / (maxValue - minValue)) * degAngleRange), - color: customColorDef(section[sectionIndex].color)}); + sectionAngles.push({ + start: (((section[sectionIndex].start + Math.abs(minValue)) / (maxValue - minValue)) * degAngleRange), + stop: (((section[sectionIndex].stop + Math.abs(minValue)) / (maxValue - minValue)) * degAngleRange), + color: customColorDef(section[sectionIndex].color) + }); } while (0 < sectionIndex); } @@ -1904,36 +1926,36 @@ var steelseries = (function () { ctx.translate(TEXT_TRANSLATE_X, 0); switch (tickLabelOrientation.type) { - case 'horizontal': - textRotationAngle = -alpha; - break; + case 'horizontal': + textRotationAngle = -alpha; + break; - case 'tangent': - textRotationAngle = (alpha <= HALF_PI + PI ? PI : 0); - break; + case 'tangent': + textRotationAngle = (alpha <= HALF_PI + PI ? PI : 0); + break; - case 'normal': - /* falls through */ - default: - textRotationAngle = HALF_PI; - break; + case 'normal': + /* falls through */ + default: + textRotationAngle = HALF_PI; + break; } ctx.rotate(textRotationAngle); switch (labelNumberFormat.format) { - case 'fractional': - ctx.fillText((valueCounter.toFixed(fractionalScaleDecimals)), 0, 0, TEXT_WIDTH); - break; + case 'fractional': + ctx.fillText((valueCounter.toFixed(fractionalScaleDecimals)), 0, 0, TEXT_WIDTH); + break; - case 'scientific': - ctx.fillText((valueCounter.toPrecision(2)), 0, 0, TEXT_WIDTH); - break; + case 'scientific': + ctx.fillText((valueCounter.toPrecision(2)), 0, 0, TEXT_WIDTH); + break; - case 'standard': - /* falls through */ - default: - ctx.fillText((valueCounter.toFixed(0)), 0, 0, TEXT_WIDTH); - break; + case 'standard': + /* falls through */ + default: + ctx.fillText((valueCounter.toFixed(0)), 0, 0, TEXT_WIDTH); + break; } ctx.translate(-TEXT_TRANSLATE_X, 0); ctx.restore(); @@ -2012,7 +2034,7 @@ var steelseries = (function () { audioElement.play(); } } else if ((value < threshold && ledBlinking && thresholdRising) || - (value > threshold && ledBlinking && !thresholdRising)) { + (value > threshold && ledBlinking && !thresholdRising)) { ledBlinking = false; blink(ledBlinking); if (playAlarm) { @@ -2055,7 +2077,7 @@ var steelseries = (function () { audioElement.play(); } } else if ((value < threshold && ledBlinking && thresholdRising) || - (value > threshold && ledBlinking && !thresholdRising)) { + (value > threshold && ledBlinking && !thresholdRising)) { ledBlinking = false; blink(ledBlinking); if (playAlarm) { @@ -2069,7 +2091,7 @@ var steelseries = (function () { }; // do we have a callback function to process? - if (callback && typeof(callback) === "function") { + if (callback && typeof (callback) === "function") { tween.onMotionFinished = callback; } @@ -2079,51 +2101,55 @@ var steelseries = (function () { }; this.setFrameDesign = function (newFrameDesign) { - resetBuffers({frame: true}); + resetBuffers({ frame: true }); frameDesign = newFrameDesign; - init({frame: true}); + init({ frame: true }); this.repaint(); return this; }; this.setBackgroundColor = function (newBackgroundColor) { - resetBuffers({background: true, - led: true}); + resetBuffers({ + background: true, + led: true + }); backgroundColor = newBackgroundColor; - init({background: true, - led: true}); + init({ + background: true, + led: true + }); this.repaint(); return this; }; this.setForegroundType = function (newForegroundType) { - resetBuffers({foreground: true}); + resetBuffers({ foreground: true }); foregroundType = newForegroundType; - init({foreground: true}); + init({ foreground: true }); this.repaint(); return this; }; this.setValueColor = function (newValueColor) { - resetBuffers({value: true}); + resetBuffers({ value: true }); valueColor = newValueColor; - init({value: true}); + init({ value: true }); this.repaint(); return this; }; this.setLedColor = function (newLedColor) { - resetBuffers({led: true}); + resetBuffers({ led: true }); ledColor = newLedColor; - init({led: true}); + init({ led: true }); this.repaint(); return this; }; this.setUserLedColor = function (newLedColor) { - resetBuffers({userLed: true}); + resetBuffers({ userLed: true }); userLedColor = newLedColor; - init({userLed: true}); + init({ userLed: true }); this.repaint(); return this; }; @@ -2177,8 +2203,8 @@ var steelseries = (function () { this.setLcdColor = function (newLcdColor) { lcdColor = newLcdColor; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -2219,8 +2245,8 @@ var steelseries = (function () { this.setMinValue = function (value) { minValue = value; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -2231,8 +2257,8 @@ var steelseries = (function () { this.setMaxValue = function (value) { maxValue = value; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -2245,8 +2271,8 @@ var steelseries = (function () { newValue = parseFloat(newValue); var targetValue = newValue < minValue ? minValue : (newValue > maxValue ? maxValue : newValue); threshold = targetValue; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -2262,16 +2288,16 @@ var steelseries = (function () { this.setTitleString = function (title) { titleString = title; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setUnitString = function (unit) { unitString = unit; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -2290,15 +2316,15 @@ var steelseries = (function () { this.setFractionalScaleDecimals = function (decimals) { fractionalScaleDecimals = parseInt(decimals, 10); - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); }; this.setLabelNumberFormat = function (format) { labelNumberFormat = format; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; @@ -2313,13 +2339,15 @@ var steelseries = (function () { fraction; if (!initialized) { - init({frame: true, - background: true, - led: true, - userLed: true, - value: true, - trend: true, - foreground: true}); + init({ + frame: true, + background: true, + led: true, + userLed: true, + value: true, + trend: true, + foreground: true + }); } mainCtx.clearRect(0, 0, size, size); @@ -2383,18 +2411,18 @@ var steelseries = (function () { // Draw the trend indicator if (trendVisible) { switch (trendIndicator.state) { - case 'up': - mainCtx.drawImage(trendUpBuffer, trendPosX, trendPosY); - break; - case 'steady': - mainCtx.drawImage(trendSteadyBuffer, trendPosX, trendPosY); - break; - case 'down': - mainCtx.drawImage(trendDownBuffer, trendPosX, trendPosY); - break; - case 'off': - mainCtx.drawImage(trendOffBuffer, trendPosX, trendPosY); - break; + case 'up': + mainCtx.drawImage(trendUpBuffer, trendPosX, trendPosY); + break; + case 'steady': + mainCtx.drawImage(trendSteadyBuffer, trendPosX, trendPosY); + break; + case 'down': + mainCtx.drawImage(trendDownBuffer, trendPosX, trendPosY); + break; + case 'off': + mainCtx.drawImage(trendOffBuffer, trendPosX, trendPosY); + break; } } @@ -2480,7 +2508,7 @@ var steelseries = (function () { mainCtx.clip(); if ((lcdColor === steelseries.LcdColor.STANDARD || lcdColor === steelseries.LcdColor.STANDARD_GREEN) && - section === null) { + section === null) { mainCtx.shadowColor = 'gray'; mainCtx.shadowOffsetX = imageHeight * 0.035; mainCtx.shadowOffsetY = imageHeight * 0.035; @@ -2638,7 +2666,7 @@ var steelseries = (function () { lcdBuffer = createLcdBackgroundImage(width, height, lcdColor); if (null !== section && 0 < section.length) { - for (sectionIndex = 0 ; sectionIndex < section.length ; sectionIndex++) { + for (sectionIndex = 0; sectionIndex < section.length; sectionIndex++) { sectionBuffer[sectionIndex] = createLcdSectionImage(width, height, section[sectionIndex].color, lcdColor); sectionForegroundColor[sectionIndex] = createSectionForegroundColor(section[sectionIndex].color); } @@ -2664,7 +2692,7 @@ var steelseries = (function () { this.setSection = function (newSection) { section = newSection; - init({background: true, foreground: true}); + init({ background: true, foreground: true }); this.repaint(); return this; }; @@ -2696,7 +2724,7 @@ var steelseries = (function () { var sectionIndex; // Draw sections if (null !== section && 0 < section.length) { - for (sectionIndex = 0 ; sectionIndex < section.length ; sectionIndex++) { + for (sectionIndex = 0; sectionIndex < section.length; sectionIndex++) { if (value >= section[sectionIndex].start && value <= section[sectionIndex].stop) { lcdBackgroundBuffer = sectionBuffer[sectionIndex]; lcdTextColor = sectionForegroundColor[sectionIndex]; @@ -2799,7 +2827,7 @@ var steelseries = (function () { // Buffer for LCD displays var lcdBuffer; - // Buffer for latest pointer images painting code + // Buffer for latest pointer /images painting code var pointerBufferLatest = createBuffer(size, size); var pointerContextLatest = pointerBufferLatest.getContext('2d'); @@ -2919,62 +2947,62 @@ var steelseries = (function () { // Draw the labels ctx.save(); switch (i) { - case 0: //E - ctx.translate(imageWidth * 0.35, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[2], 0, 0); - ctx.translate(-imageWidth * 0.35, 0); - break; - case 45: //SE - ctx.translate(imageWidth * 0.29, 0); - ctx.rotate(HALF_PI); - ctx.font = smlFont; - ctx.fillText(pointSymbols[3], 0, 0); - ctx.translate(-imageWidth * 0.29, 0); - break; - case 90: //S - ctx.translate(imageWidth * 0.35, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[4], 0, 0); - ctx.translate(-imageWidth * 0.35, 0); - break; - case 135: //SW - ctx.translate(imageWidth * 0.29, 0); - ctx.rotate(HALF_PI); - ctx.font = smlFont; - ctx.fillText(pointSymbols[5], 0, 0); - ctx.translate(-imageWidth * 0.29, 0); - break; - case 180: //W - ctx.translate(imageWidth * 0.35, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[6], 0, 0); - ctx.translate(-imageWidth * 0.35, 0); - break; - case 225: //NW - ctx.translate(imageWidth * 0.29, 0); - ctx.rotate(HALF_PI); - ctx.font = smlFont; - ctx.fillText(pointSymbols[7], 0, 0); - ctx.translate(-imageWidth * 0.29, 0); - break; - case 270: //N - ctx.translate(imageWidth * 0.35, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[0], 0, 0); - ctx.translate(-imageWidth * 0.35, 0); - break; - case 315: //NE - ctx.translate(imageWidth * 0.29, 0); - ctx.rotate(HALF_PI); - ctx.font = smlFont; - ctx.fillText(pointSymbols[1], 0, 0); - ctx.translate(-imageWidth * 0.29, 0); - break; + case 0: //E + ctx.translate(imageWidth * 0.35, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[2], 0, 0); + ctx.translate(-imageWidth * 0.35, 0); + break; + case 45: //SE + ctx.translate(imageWidth * 0.29, 0); + ctx.rotate(HALF_PI); + ctx.font = smlFont; + ctx.fillText(pointSymbols[3], 0, 0); + ctx.translate(-imageWidth * 0.29, 0); + break; + case 90: //S + ctx.translate(imageWidth * 0.35, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[4], 0, 0); + ctx.translate(-imageWidth * 0.35, 0); + break; + case 135: //SW + ctx.translate(imageWidth * 0.29, 0); + ctx.rotate(HALF_PI); + ctx.font = smlFont; + ctx.fillText(pointSymbols[5], 0, 0); + ctx.translate(-imageWidth * 0.29, 0); + break; + case 180: //W + ctx.translate(imageWidth * 0.35, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[6], 0, 0); + ctx.translate(-imageWidth * 0.35, 0); + break; + case 225: //NW + ctx.translate(imageWidth * 0.29, 0); + ctx.rotate(HALF_PI); + ctx.font = smlFont; + ctx.fillText(pointSymbols[7], 0, 0); + ctx.translate(-imageWidth * 0.29, 0); + break; + case 270: //N + ctx.translate(imageWidth * 0.35, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[0], 0, 0); + ctx.translate(-imageWidth * 0.35, 0); + break; + case 315: //NE + ctx.translate(imageWidth * 0.29, 0); + ctx.rotate(HALF_PI); + ctx.font = smlFont; + ctx.fillText(pointSymbols[1], 0, 0); + ctx.translate(-imageWidth * 0.29, 0); + break; } ctx.restore(); @@ -3006,69 +3034,69 @@ var steelseries = (function () { if (pointSymbolsVisible) { switch (i) { - case 360: - ctx.translate(CARDINAL_TRANSLATE_X, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[2], 0, 0, TEXT_WIDTH); - ctx.translate(-CARDINAL_TRANSLATE_X, 0); - break; - case 90: - ctx.translate(CARDINAL_TRANSLATE_X, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[4], 0, 0, TEXT_WIDTH); - ctx.translate(-CARDINAL_TRANSLATE_X, 0); - break; - case 180: - ctx.translate(CARDINAL_TRANSLATE_X, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[6], 0, 0, TEXT_WIDTH); - ctx.translate(-CARDINAL_TRANSLATE_X, 0); - break; - case 270: - ctx.translate(CARDINAL_TRANSLATE_X, 0); - ctx.rotate(HALF_PI); - ctx.font = stdFont; - ctx.fillText(pointSymbols[0], 0, 0, TEXT_WIDTH); - ctx.translate(-CARDINAL_TRANSLATE_X, 0); - break; - - case 5: - case 85: - case 95: - case 175: - case 185: - case 265: - case 275: - case 355: - //leave room for ordinal labels - break; - - default: - if ((i + 90) % 20) { - ctx.lineWidth = ((i + 90) % 5) ? 1.5 : 1; - ctx.beginPath(); - ctx.moveTo(OUTER_POINT, 0); - to = (i + 90) % 10 ? MINOR_INNER_POINT : MAJOR_INNER_POINT; - ctx.lineTo(to, 0); - ctx.closePath(); - ctx.stroke(); - } else { - ctx.lineWidth = 1.5; - ctx.beginPath(); - ctx.moveTo(OUTER_POINT, 0); - ctx.lineTo(MAJOR_INNER_POINT, 0); - ctx.closePath(); - ctx.stroke(); - val = (i + 90) % 360; - ctx.translate(TEXT_TRANSLATE_X, 0); + case 360: + ctx.translate(CARDINAL_TRANSLATE_X, 0); ctx.rotate(HALF_PI); - ctx.font = smlFont; - ctx.fillText(('0'.substring(val >= 100) + val), 0, 0, TEXT_WIDTH); - ctx.translate(-TEXT_TRANSLATE_X, 0); - } + ctx.font = stdFont; + ctx.fillText(pointSymbols[2], 0, 0, TEXT_WIDTH); + ctx.translate(-CARDINAL_TRANSLATE_X, 0); + break; + case 90: + ctx.translate(CARDINAL_TRANSLATE_X, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[4], 0, 0, TEXT_WIDTH); + ctx.translate(-CARDINAL_TRANSLATE_X, 0); + break; + case 180: + ctx.translate(CARDINAL_TRANSLATE_X, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[6], 0, 0, TEXT_WIDTH); + ctx.translate(-CARDINAL_TRANSLATE_X, 0); + break; + case 270: + ctx.translate(CARDINAL_TRANSLATE_X, 0); + ctx.rotate(HALF_PI); + ctx.font = stdFont; + ctx.fillText(pointSymbols[0], 0, 0, TEXT_WIDTH); + ctx.translate(-CARDINAL_TRANSLATE_X, 0); + break; + + case 5: + case 85: + case 95: + case 175: + case 185: + case 265: + case 275: + case 355: + //leave room for ordinal labels + break; + + default: + if ((i + 90) % 20) { + ctx.lineWidth = ((i + 90) % 5) ? 1.5 : 1; + ctx.beginPath(); + ctx.moveTo(OUTER_POINT, 0); + to = (i + 90) % 10 ? MINOR_INNER_POINT : MAJOR_INNER_POINT; + ctx.lineTo(to, 0); + ctx.closePath(); + ctx.stroke(); + } else { + ctx.lineWidth = 1.5; + ctx.beginPath(); + ctx.moveTo(OUTER_POINT, 0); + ctx.lineTo(MAJOR_INNER_POINT, 0); + ctx.closePath(); + ctx.stroke(); + val = (i + 90) % 360; + ctx.translate(TEXT_TRANSLATE_X, 0); + ctx.rotate(HALF_PI); + ctx.font = smlFont; + ctx.fillText(('0'.substring(val >= 100) + val), 0, 0, TEXT_WIDTH); + ctx.translate(-TEXT_TRANSLATE_X, 0); + } } } else { @@ -3299,7 +3327,7 @@ var steelseries = (function () { requestAnimFrame(gauge.repaint); } // do we have a callback function to process? - if (callback && typeof(callback) === "function") { + if (callback && typeof (callback) === "function") { callback(); } }; @@ -3351,7 +3379,7 @@ var steelseries = (function () { requestAnimFrame(gauge.repaint); } // do we have a callback function to process? - if (callback && typeof(callback) === "function") { + if (callback && typeof (callback) === "function") { callback(); } }; @@ -3371,115 +3399,121 @@ var steelseries = (function () { this.setArea = function (areaVal) { area = areaVal; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setSection = function (areaSec) { section = areaSec; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setFrameDesign = function (newFrameDesign) { frameDesign = newFrameDesign; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setBackgroundColor = function (newBackgroundColor) { backgroundColor = newBackgroundColor; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setForegroundType = function (newForegroundType) { - resetBuffers({foreground: true}); + resetBuffers({ foreground: true }); foregroundType = newForegroundType; - init({foreground: true}); + init({ foreground: true }); this.repaint(); return this; }; this.setPointerColor = function (newPointerColor) { - resetBuffers({pointer: true}); + resetBuffers({ pointer: true }); pointerColor = newPointerColor; - init({pointer: true}); + init({ pointer: true }); this.repaint(); return this; }; this.setPointerColorAverage = function (newPointerColor) { - resetBuffers({pointer: true}); + resetBuffers({ pointer: true }); pointerColorAverage = newPointerColor; - init({pointer: true}); + init({ pointer: true }); this.repaint(); return this; }; this.setPointerType = function (newPointerType) { pointerTypeLatest = newPointerType; - resetBuffers({pointer: true, - foreground: true - }); - init({pointer: true, - foreground: true - }); + resetBuffers({ + pointer: true, + foreground: true + }); + init({ + pointer: true, + foreground: true + }); this.repaint(); return this; }; this.setPointerTypeAverage = function (newPointerType) { pointerTypeAverage = newPointerType; - resetBuffers({pointer: true, - foreground: true - }); - init({pointer: true, - foreground: true - }); + resetBuffers({ + pointer: true, + foreground: true + }); + init({ + pointer: true, + foreground: true + }); this.repaint(); return this; }; this.setPointSymbols = function (newPointSymbols) { pointSymbols = newPointSymbols; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setLcdColor = function (newLcdColor) { lcdColor = newLcdColor; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.setLcdTitleStrings = function (titles) { lcdTitleStrings = titles; - resetBuffers({background: true}); - init({background: true}); + resetBuffers({ background: true }); + init({ background: true }); this.repaint(); return this; }; this.repaint = function () { if (!initialized) { - init({frame: true, - background: true, - led: true, - pointer: true, - foreground: true}); + init({ + frame: true, + background: true, + led: true, + pointer: true, + foreground: true + }); } mainCtx.clearRect(0, 0, mainCtx.canvas.width, mainCtx.canvas.height); @@ -3513,7 +3547,7 @@ var steelseries = (function () { // Draw the pointer mainCtx.drawImage(pointerBufferAverage, 0, 0); // Define rotation angle difference for average pointer - angleLatest = valueLatest * angleStep - angleAverage; + angleLatest = valueLatest * angleStep - angleAverage; mainCtx.translate(centerX, centerY); mainCtx.rotate(angleLatest); mainCtx.translate(-centerX, -centerY); @@ -3669,7 +3703,7 @@ var steelseries = (function () { foregroundBuffer, foregroundContext, digitBuffer, digitContext, decimalBuffer, decimalContext; - // End of variables + // End of variables // Get the canvas context and clear it if (_context) { @@ -3791,7 +3825,7 @@ var steelseries = (function () { function drawDigits() { var pos = 1, - val = value, i, num, numb, frac, prevNum; + val = value, i, num, numb, frac, prevNum; // do not use Math.pow() - rounding errors! for (i = 0; i < decimals; i++) { @@ -3840,7 +3874,7 @@ var steelseries = (function () { }; // do we have a callback function to process? - if (callback && typeof(callback) === "function") { + if (callback && typeof (callback) === "function") { tween.onMotionFinished = callback; } @@ -3911,151 +3945,151 @@ var steelseries = (function () { ctx.translate(-centerX, -centerY); -/* - // PATH1_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.560747, imageHeight * 0.584112); - ctx.lineTo(imageWidth * 0.640186, imageHeight * 0.644859); - ctx.lineTo(imageWidth * 0.584112, imageHeight * 0.560747); - ctx.lineTo(imageWidth * 0.560747, imageHeight * 0.584112); - ctx.closePath(); - ctx.fillStyle = fillColorPath; - ctx.fill(); - ctx.stroke(); - - // PATH2_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.411214, imageHeight * 0.560747); - ctx.lineTo(imageWidth * 0.355140, imageHeight * 0.644859); - ctx.lineTo(imageWidth * 0.439252, imageHeight * 0.588785); - ctx.lineTo(imageWidth * 0.411214, imageHeight * 0.560747); - ctx.closePath(); - ctx.fillStyle = fillColorPath; - ctx.fill(); - ctx.stroke(); - - // PATH3_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.584112, imageHeight * 0.443925); - ctx.lineTo(imageWidth * 0.640186, imageHeight * 0.359813); - ctx.lineTo(imageWidth * 0.560747, imageHeight * 0.420560); - ctx.lineTo(imageWidth * 0.584112, imageHeight * 0.443925); - ctx.closePath(); - ctx.fillStyle = fillColorPath; - ctx.fill(); - ctx.stroke(); - - // PATH4_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.439252, imageHeight * 0.415887); - ctx.lineTo(imageWidth * 0.355140, imageHeight * 0.359813); - ctx.lineTo(imageWidth * 0.415887, imageHeight * 0.439252); - ctx.lineTo(imageWidth * 0.439252, imageHeight * 0.415887); - ctx.closePath(); - ctx.fillStyle = fillColorPath; - ctx.fill(); - ctx.stroke(); - - // PATH5_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.523364, imageHeight * 0.397196); - ctx.lineTo(imageWidth * 0.5, imageHeight * 0.196261); - ctx.lineTo(imageWidth * 0.471962, imageHeight * 0.397196); - ctx.lineTo(imageWidth * 0.523364, imageHeight * 0.397196); - ctx.closePath(); - var PATH5_2_GRADIENT = ctx.createLinearGradient(0.476635 * imageWidth, 0, 0.518691 * imageWidth, 0); - PATH5_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); - PATH5_2_GRADIENT.addColorStop(0.48, 'rgb(222, 223, 218)'); - PATH5_2_GRADIENT.addColorStop(0.49, backgroundColor.symbolColor.getRgbaColor()); - PATH5_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); - ctx.fillStyle = PATH5_2_GRADIENT; - ctx.fill(); - ctx.stroke(); - - // PATH6_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.471962, imageHeight * 0.607476); - ctx.lineTo(imageWidth * 0.5, imageHeight * 0.813084); - ctx.lineTo(imageWidth * 0.523364, imageHeight * 0.607476); - ctx.lineTo(imageWidth * 0.471962, imageHeight * 0.607476); - ctx.closePath(); - var PATH6_2_GRADIENT = ctx.createLinearGradient(0.518691 * imageWidth, 0, (0.518691 + -0.037383) * imageWidth, 0); - PATH6_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); - PATH6_2_GRADIENT.addColorStop(0.56, 'rgb(222, 223, 218)'); - PATH6_2_GRADIENT.addColorStop(0.5601, backgroundColor.symbolColor.getRgbaColor()); - PATH6_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); - ctx.fillStyle = PATH6_2_GRADIENT; - ctx.lineWidth = 1; - ctx.lineCap = 'square'; - ctx.lineJoin = 'miter'; - ctx.strokeStyle = backgroundColor.symbolColor.getRgbaColor(); - ctx.fill(); - ctx.stroke(); - - // PATH7_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.602803, imageHeight * 0.528037); - ctx.lineTo(imageWidth * 0.803738, imageHeight * 0.5); - ctx.lineTo(imageWidth * 0.602803, imageHeight * 0.476635); - ctx.lineTo(imageWidth * 0.602803, imageHeight * 0.528037); - ctx.closePath(); - var PATH7_2_GRADIENT = ctx.createLinearGradient(0, 0.485981 * imageHeight, 0, 0.514018 * imageHeight); - PATH7_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); - PATH7_2_GRADIENT.addColorStop(0.48, 'rgb(222, 223, 218)'); - PATH7_2_GRADIENT.addColorStop(0.49, backgroundColor.symbolColor.getRgbaColor()); - PATH7_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); - ctx.fillStyle = PATH7_2_GRADIENT; - ctx.fill(); - ctx.stroke(); - - // PATH8_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.392523, imageHeight * 0.476635); - ctx.lineTo(imageWidth * 0.191588, imageHeight * 0.5); - ctx.lineTo(imageWidth * 0.392523, imageHeight * 0.528037); - ctx.lineTo(imageWidth * 0.392523, imageHeight * 0.476635); - ctx.closePath(); - var PATH8_2_GRADIENT = ctx.createLinearGradient(0, 0.528037 * imageHeight, 0, 0.485981 * imageHeight); - PATH8_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); - PATH8_2_GRADIENT.addColorStop(0.52, 'rgb(222, 223, 218)'); - PATH8_2_GRADIENT.addColorStop(0.53, backgroundColor.symbolColor.getRgbaColor()); - PATH8_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); - ctx.fillStyle = PATH8_2_GRADIENT; - ctx.fill(); - ctx.stroke(); - - // PATH9_2 - ctx.save(); - ctx.beginPath(); - ctx.moveTo(imageWidth * 0.406542, imageHeight * 0.504672); - ctx.bezierCurveTo(imageWidth * 0.406542, imageHeight * 0.453271, imageWidth * 0.448598, imageHeight * 0.411214, imageWidth * 0.5, imageHeight * 0.411214); - ctx.bezierCurveTo(imageWidth * 0.546728, imageHeight * 0.411214, imageWidth * 0.588785, imageHeight * 0.453271, imageWidth * 0.588785, imageHeight * 0.504672); - ctx.bezierCurveTo(imageWidth * 0.588785, imageHeight * 0.551401, imageWidth * 0.546728, imageHeight * 0.593457, imageWidth * 0.5, imageHeight * 0.593457); - ctx.bezierCurveTo(imageWidth * 0.448598, imageHeight * 0.593457, imageWidth * 0.406542, imageHeight * 0.551401, imageWidth * 0.406542, imageHeight * 0.504672); - ctx.closePath(); - ctx.moveTo(imageWidth * 0.387850, imageHeight * 0.504672); - ctx.bezierCurveTo(imageWidth * 0.387850, imageHeight * 0.560747, imageWidth * 0.439252, imageHeight * 0.612149, imageWidth * 0.5, imageHeight * 0.612149); - ctx.bezierCurveTo(imageWidth * 0.556074, imageHeight * 0.612149, imageWidth * 0.607476, imageHeight * 0.560747, imageWidth * 0.607476, imageHeight * 0.504672); - ctx.bezierCurveTo(imageWidth * 0.607476, imageHeight * 0.443925, imageWidth * 0.556074, imageHeight * 0.392523, imageWidth * 0.5, imageHeight * 0.392523); - ctx.bezierCurveTo(imageWidth * 0.439252, imageHeight * 0.392523, imageWidth * 0.387850, imageHeight * 0.443925, imageWidth * 0.387850, imageHeight * 0.504672); - ctx.closePath(); - ctx.fillStyle = fillColorPath; - ctx.lineWidth = 1; - ctx.lineCap = 'square'; - ctx.lineJoin = 'miter'; - ctx.strokeStyle = backgroundColor.symbolColor.getRgbaColor(); - ctx.fill(); - ctx.stroke(); - ctx.restore(); -*/ + /* + // PATH1_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.560747, imageHeight * 0.584112); + ctx.lineTo(imageWidth * 0.640186, imageHeight * 0.644859); + ctx.lineTo(imageWidth * 0.584112, imageHeight * 0.560747); + ctx.lineTo(imageWidth * 0.560747, imageHeight * 0.584112); + ctx.closePath(); + ctx.fillStyle = fillColorPath; + ctx.fill(); + ctx.stroke(); + + // PATH2_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.411214, imageHeight * 0.560747); + ctx.lineTo(imageWidth * 0.355140, imageHeight * 0.644859); + ctx.lineTo(imageWidth * 0.439252, imageHeight * 0.588785); + ctx.lineTo(imageWidth * 0.411214, imageHeight * 0.560747); + ctx.closePath(); + ctx.fillStyle = fillColorPath; + ctx.fill(); + ctx.stroke(); + + // PATH3_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.584112, imageHeight * 0.443925); + ctx.lineTo(imageWidth * 0.640186, imageHeight * 0.359813); + ctx.lineTo(imageWidth * 0.560747, imageHeight * 0.420560); + ctx.lineTo(imageWidth * 0.584112, imageHeight * 0.443925); + ctx.closePath(); + ctx.fillStyle = fillColorPath; + ctx.fill(); + ctx.stroke(); + + // PATH4_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.439252, imageHeight * 0.415887); + ctx.lineTo(imageWidth * 0.355140, imageHeight * 0.359813); + ctx.lineTo(imageWidth * 0.415887, imageHeight * 0.439252); + ctx.lineTo(imageWidth * 0.439252, imageHeight * 0.415887); + ctx.closePath(); + ctx.fillStyle = fillColorPath; + ctx.fill(); + ctx.stroke(); + + // PATH5_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.523364, imageHeight * 0.397196); + ctx.lineTo(imageWidth * 0.5, imageHeight * 0.196261); + ctx.lineTo(imageWidth * 0.471962, imageHeight * 0.397196); + ctx.lineTo(imageWidth * 0.523364, imageHeight * 0.397196); + ctx.closePath(); + var PATH5_2_GRADIENT = ctx.createLinearGradient(0.476635 * imageWidth, 0, 0.518691 * imageWidth, 0); + PATH5_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); + PATH5_2_GRADIENT.addColorStop(0.48, 'rgb(222, 223, 218)'); + PATH5_2_GRADIENT.addColorStop(0.49, backgroundColor.symbolColor.getRgbaColor()); + PATH5_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); + ctx.fillStyle = PATH5_2_GRADIENT; + ctx.fill(); + ctx.stroke(); + + // PATH6_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.471962, imageHeight * 0.607476); + ctx.lineTo(imageWidth * 0.5, imageHeight * 0.813084); + ctx.lineTo(imageWidth * 0.523364, imageHeight * 0.607476); + ctx.lineTo(imageWidth * 0.471962, imageHeight * 0.607476); + ctx.closePath(); + var PATH6_2_GRADIENT = ctx.createLinearGradient(0.518691 * imageWidth, 0, (0.518691 + -0.037383) * imageWidth, 0); + PATH6_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); + PATH6_2_GRADIENT.addColorStop(0.56, 'rgb(222, 223, 218)'); + PATH6_2_GRADIENT.addColorStop(0.5601, backgroundColor.symbolColor.getRgbaColor()); + PATH6_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); + ctx.fillStyle = PATH6_2_GRADIENT; + ctx.lineWidth = 1; + ctx.lineCap = 'square'; + ctx.lineJoin = 'miter'; + ctx.strokeStyle = backgroundColor.symbolColor.getRgbaColor(); + ctx.fill(); + ctx.stroke(); + + // PATH7_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.602803, imageHeight * 0.528037); + ctx.lineTo(imageWidth * 0.803738, imageHeight * 0.5); + ctx.lineTo(imageWidth * 0.602803, imageHeight * 0.476635); + ctx.lineTo(imageWidth * 0.602803, imageHeight * 0.528037); + ctx.closePath(); + var PATH7_2_GRADIENT = ctx.createLinearGradient(0, 0.485981 * imageHeight, 0, 0.514018 * imageHeight); + PATH7_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); + PATH7_2_GRADIENT.addColorStop(0.48, 'rgb(222, 223, 218)'); + PATH7_2_GRADIENT.addColorStop(0.49, backgroundColor.symbolColor.getRgbaColor()); + PATH7_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); + ctx.fillStyle = PATH7_2_GRADIENT; + ctx.fill(); + ctx.stroke(); + + // PATH8_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.392523, imageHeight * 0.476635); + ctx.lineTo(imageWidth * 0.191588, imageHeight * 0.5); + ctx.lineTo(imageWidth * 0.392523, imageHeight * 0.528037); + ctx.lineTo(imageWidth * 0.392523, imageHeight * 0.476635); + ctx.closePath(); + var PATH8_2_GRADIENT = ctx.createLinearGradient(0, 0.528037 * imageHeight, 0, 0.485981 * imageHeight); + PATH8_2_GRADIENT.addColorStop(0, 'rgb(222, 223, 218)'); + PATH8_2_GRADIENT.addColorStop(0.52, 'rgb(222, 223, 218)'); + PATH8_2_GRADIENT.addColorStop(0.53, backgroundColor.symbolColor.getRgbaColor()); + PATH8_2_GRADIENT.addColorStop(1, backgroundColor.symbolColor.getRgbaColor()); + ctx.fillStyle = PATH8_2_GRADIENT; + ctx.fill(); + ctx.stroke(); + + // PATH9_2 + ctx.save(); + ctx.beginPath(); + ctx.moveTo(imageWidth * 0.406542, imageHeight * 0.504672); + ctx.bezierCurveTo(imageWidth * 0.406542, imageHeight * 0.453271, imageWidth * 0.448598, imageHeight * 0.411214, imageWidth * 0.5, imageHeight * 0.411214); + ctx.bezierCurveTo(imageWidth * 0.546728, imageHeight * 0.411214, imageWidth * 0.588785, imageHeight * 0.453271, imageWidth * 0.588785, imageHeight * 0.504672); + ctx.bezierCurveTo(imageWidth * 0.588785, imageHeight * 0.551401, imageWidth * 0.546728, imageHeight * 0.593457, imageWidth * 0.5, imageHeight * 0.593457); + ctx.bezierCurveTo(imageWidth * 0.448598, imageHeight * 0.593457, imageWidth * 0.406542, imageHeight * 0.551401, imageWidth * 0.406542, imageHeight * 0.504672); + ctx.closePath(); + ctx.moveTo(imageWidth * 0.387850, imageHeight * 0.504672); + ctx.bezierCurveTo(imageWidth * 0.387850, imageHeight * 0.560747, imageWidth * 0.439252, imageHeight * 0.612149, imageWidth * 0.5, imageHeight * 0.612149); + ctx.bezierCurveTo(imageWidth * 0.556074, imageHeight * 0.612149, imageWidth * 0.607476, imageHeight * 0.560747, imageWidth * 0.607476, imageHeight * 0.504672); + ctx.bezierCurveTo(imageWidth * 0.607476, imageHeight * 0.443925, imageWidth * 0.556074, imageHeight * 0.392523, imageWidth * 0.5, imageHeight * 0.392523); + ctx.bezierCurveTo(imageWidth * 0.439252, imageHeight * 0.392523, imageWidth * 0.387850, imageHeight * 0.443925, imageWidth * 0.387850, imageHeight * 0.504672); + ctx.closePath(); + ctx.fillStyle = fillColorPath; + ctx.lineWidth = 1; + ctx.lineCap = 'square'; + ctx.lineJoin = 'miter'; + ctx.strokeStyle = backgroundColor.symbolColor.getRgbaColor(); + ctx.fill(); + ctx.stroke(); + ctx.restore(); + */ // Replacement code, not quite the same but much smaller! for (i = 0; 360 >= i; i += 90) { @@ -4113,354 +4147,354 @@ var steelseries = (function () { ptrCtx = ptrBuffer.getContext('2d'); switch (ptrType.type) { - case 'type2': - grad = ptrCtx.createLinearGradient(0, size * 0.471962, 0, size * 0.130841); - grad.addColorStop(0, lblColor.getRgbaColor()); - grad.addColorStop(0.36, lblColor.getRgbaColor()); - grad.addColorStop(0.361, ptrColor.light.getRgbaColor()); - grad.addColorStop(1, ptrColor.light.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.518691, size * 0.471962); - ptrCtx.lineTo(size * 0.509345, size * 0.462616); - ptrCtx.lineTo(size * 0.509345, size * 0.341121); - ptrCtx.lineTo(size * 0.504672, size * 0.130841); - ptrCtx.lineTo(size * 0.495327, size * 0.130841); - ptrCtx.lineTo(size * 0.490654, size * 0.341121); - ptrCtx.lineTo(size * 0.490654, size * 0.462616); - ptrCtx.lineTo(size * 0.481308, size * 0.471962); - ptrCtx.closePath(); - ptrCtx.fill(); - break; - - case 'type3': - ptrCtx.beginPath(); - ptrCtx.rect(size * 0.495327, size * 0.130841, size * 0.009345, size * 0.373831); - ptrCtx.closePath(); - ptrCtx.fillStyle = ptrColor.light.getRgbaColor(); - ptrCtx.fill(); - break; - - case 'type4': - grad = ptrCtx.createLinearGradient(0.467289 * size, 0, 0.528036 * size, 0); - grad.addColorStop(0, ptrColor.dark.getRgbaColor()); - grad.addColorStop(0.51, ptrColor.dark.getRgbaColor()); - grad.addColorStop(0.52, ptrColor.light.getRgbaColor()); - grad.addColorStop(1, ptrColor.light.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.5, size * 0.126168); - ptrCtx.lineTo(size * 0.514018, size * 0.135514); - ptrCtx.lineTo(size * 0.532710, size * 0.5); - ptrCtx.lineTo(size * 0.523364, size * 0.602803); - ptrCtx.lineTo(size * 0.476635, size * 0.602803); - ptrCtx.lineTo(size * 0.467289, size * 0.5); - ptrCtx.lineTo(size * 0.485981, size * 0.135514); - ptrCtx.lineTo(size * 0.5, size * 0.126168); - ptrCtx.closePath(); - ptrCtx.fill(); - break; - - case 'type5': - grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); - grad.addColorStop(0, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.medium.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.5, size * 0.495327); - ptrCtx.lineTo(size * 0.528037, size * 0.495327); - ptrCtx.lineTo(size * 0.5, size * 0.149532); - ptrCtx.lineTo(size * 0.471962, size * 0.495327); - ptrCtx.lineTo(size * 0.5, size * 0.495327); - ptrCtx.closePath(); - ptrCtx.fill(); - - ptrCtx.lineWidth = 1; - ptrCtx.lineCap = 'square'; - ptrCtx.lineJoin = 'miter'; - ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); - ptrCtx.stroke(); - break; - - case 'type6': - ptrCtx.fillStyle = ptrColor.medium.getRgbaColor(); - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.481308, size * 0.485981); - ptrCtx.lineTo(size * 0.481308, size * 0.392523); - ptrCtx.lineTo(size * 0.485981, size * 0.317757); - ptrCtx.lineTo(size * 0.495327, size * 0.130841); - ptrCtx.lineTo(size * 0.504672, size * 0.130841); - ptrCtx.lineTo(size * 0.514018, size * 0.317757); - ptrCtx.lineTo(size * 0.518691, size * 0.387850); - ptrCtx.lineTo(size * 0.518691, size * 0.485981); - ptrCtx.lineTo(size * 0.504672, size * 0.485981); - ptrCtx.lineTo(size * 0.504672, size * 0.387850); - ptrCtx.lineTo(size * 0.5, size * 0.317757); - ptrCtx.lineTo(size * 0.495327, size * 0.392523); - ptrCtx.lineTo(size * 0.495327, size * 0.485981); - ptrCtx.lineTo(size * 0.481308, size * 0.485981); - ptrCtx.closePath(); - ptrCtx.fill(); - break; - - case 'type7': - grad = ptrCtx.createLinearGradient(0.481308 * size, 0, 0.518691 * size, 0); - grad.addColorStop(0, ptrColor.dark.getRgbaColor()); - grad.addColorStop(1, ptrColor.medium.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.490654, size * 0.130841); - ptrCtx.lineTo(size * 0.481308, size * 0.5); - ptrCtx.lineTo(size * 0.518691, size * 0.5); - ptrCtx.lineTo(size * 0.504672, size * 0.130841); - ptrCtx.lineTo(size * 0.490654, size * 0.130841); - ptrCtx.closePath(); - ptrCtx.fill(); - break; - - case 'type8': - grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); - grad.addColorStop(0, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.medium.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.5, size * 0.532710); - ptrCtx.lineTo(size * 0.532710, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.532710, size * 0.5, size * 0.509345, size * 0.457943, size * 0.5, size * 0.149532); - ptrCtx.bezierCurveTo(size * 0.490654, size * 0.457943, size * 0.467289, size * 0.5, size * 0.467289, size * 0.5); - ptrCtx.lineTo(size * 0.5, size * 0.532710); - ptrCtx.closePath(); - ptrCtx.fill(); - ptrCtx.stroke(); - break; - - case 'type9': - grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); - grad.addColorStop(0, 'rgb(50, 50, 50)'); - grad.addColorStop(0.5, '#666666'); - grad.addColorStop(1, 'rgb(50, 50, 50)'); - ptrCtx.fillStyle = grad; - ptrCtx.strokeStyle = '#2E2E2E'; - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.495327, size * 0.233644); - ptrCtx.lineTo(size * 0.504672, size * 0.233644); - ptrCtx.lineTo(size * 0.514018, size * 0.439252); - ptrCtx.lineTo(size * 0.485981, size * 0.439252); - ptrCtx.lineTo(size * 0.495327, size * 0.233644); - ptrCtx.closePath(); - ptrCtx.moveTo(size * 0.490654, size * 0.130841); - ptrCtx.lineTo(size * 0.471962, size * 0.471962); - ptrCtx.lineTo(size * 0.471962, size * 0.528037); - ptrCtx.bezierCurveTo(size * 0.471962, size * 0.528037, size * 0.476635, size * 0.602803, size * 0.476635, size * 0.602803); - ptrCtx.bezierCurveTo(size * 0.476635, size * 0.607476, size * 0.481308, size * 0.607476, size * 0.5, size * 0.607476); - ptrCtx.bezierCurveTo(size * 0.518691, size * 0.607476, size * 0.523364, size * 0.607476, size * 0.523364, size * 0.602803); - ptrCtx.bezierCurveTo(size * 0.523364, size * 0.602803, size * 0.528037, size * 0.528037, size * 0.528037, size * 0.528037); - ptrCtx.lineTo(size * 0.528037, size * 0.471962); - ptrCtx.lineTo(size * 0.509345, size * 0.130841); - ptrCtx.lineTo(size * 0.490654, size * 0.130841); - ptrCtx.closePath(); - ptrCtx.fill(); - - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.495327, size * 0.219626); - ptrCtx.lineTo(size * 0.504672, size * 0.219626); - ptrCtx.lineTo(size * 0.504672, size * 0.135514); - ptrCtx.lineTo(size * 0.495327, size * 0.135514); - ptrCtx.lineTo(size * 0.495327, size * 0.219626); - ptrCtx.closePath(); - - ptrCtx.fillStyle = ptrColor.medium.getRgbaColor(); - ptrCtx.fill(); - break; - - case 'type10': - // POINTER_TYPE10 - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.5, size * 0.149532); - ptrCtx.bezierCurveTo(size * 0.5, size * 0.149532, size * 0.443925, size * 0.490654, size * 0.443925, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.443925, size * 0.532710, size * 0.467289, size * 0.556074, size * 0.5, size * 0.556074); - ptrCtx.bezierCurveTo(size * 0.532710, size * 0.556074, size * 0.556074, size * 0.532710, size * 0.556074, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.556074, size * 0.490654, size * 0.5, size * 0.149532, size * 0.5, size * 0.149532); - ptrCtx.closePath(); - grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); - grad.addColorStop(0, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.medium.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.strokeStyle = ptrColor.medium.getRgbaColor(); - ptrCtx.lineWidth = 1; - ptrCtx.lineCap = 'square'; - ptrCtx.lineJoin = 'miter'; - ptrCtx.fill(); - ptrCtx.stroke(); - break; - - case 'type11': - // POINTER_TYPE11 - ptrCtx.beginPath(); - ptrCtx.moveTo(0.5 * size, 0.168224 * size); - ptrCtx.lineTo(0.485981 * size, 0.5 * size); - ptrCtx.bezierCurveTo(0.485981 * size, 0.5 * size, 0.481308 * size, 0.584112 * size, 0.5 * size, 0.584112 * size); - ptrCtx.bezierCurveTo(0.514018 * size, 0.584112 * size, 0.509345 * size, 0.5 * size, 0.509345 * size, 0.5 * size); - ptrCtx.lineTo(0.5 * size, 0.168224 * size); - ptrCtx.closePath(); - grad = ptrCtx.createLinearGradient(0, 0.168224 * size, 0, 0.584112 * size); - grad.addColorStop(0, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.dark.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); - ptrCtx.fill(); - ptrCtx.stroke(); - break; - - case 'type12': - // POINTER_TYPE12 - ptrCtx.beginPath(); - ptrCtx.moveTo(0.5 * size, 0.168224 * size); - ptrCtx.lineTo(0.485981 * size, 0.5 * size); - ptrCtx.lineTo(0.5 * size, 0.504672 * size); - ptrCtx.lineTo(0.509345 * size, 0.5 * size); - ptrCtx.lineTo(0.5 * size, 0.168224 * size); - ptrCtx.closePath(); - grad = ptrCtx.createLinearGradient(0, 0.168224 * size, 0, 0.504672 * size); - grad.addColorStop(0, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.dark.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); - ptrCtx.fill(); - ptrCtx.stroke(); - break; - - case 'type13': - // POINTER_TYPE13 - case 'type14': - // POINTER_TYPE14 (same shape as 13) - ptrCtx.beginPath(); - ptrCtx.moveTo(0.485981 * size, 0.168224 * size); - ptrCtx.lineTo(0.5 * size, 0.130841 * size); - ptrCtx.lineTo(0.509345 * size, 0.168224 * size); - ptrCtx.lineTo(0.509345 * size, 0.509345 * size); - ptrCtx.lineTo(0.485981 * size, 0.509345 * size); - ptrCtx.lineTo(0.485981 * size, 0.168224 * size); - ptrCtx.closePath(); - if (ptrType.type === 'type13') { - // TYPE13 - grad = ptrCtx.createLinearGradient(0, 0.5 * size, 0, 0.130841 * size); + case 'type2': + grad = ptrCtx.createLinearGradient(0, size * 0.471962, 0, size * 0.130841); grad.addColorStop(0, lblColor.getRgbaColor()); - grad.addColorStop(0.85, lblColor.getRgbaColor()); - grad.addColorStop(0.85, ptrColor.medium.getRgbaColor()); + grad.addColorStop(0.36, lblColor.getRgbaColor()); + grad.addColorStop(0.361, ptrColor.light.getRgbaColor()); + grad.addColorStop(1, ptrColor.light.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.518691, size * 0.471962); + ptrCtx.lineTo(size * 0.509345, size * 0.462616); + ptrCtx.lineTo(size * 0.509345, size * 0.341121); + ptrCtx.lineTo(size * 0.504672, size * 0.130841); + ptrCtx.lineTo(size * 0.495327, size * 0.130841); + ptrCtx.lineTo(size * 0.490654, size * 0.341121); + ptrCtx.lineTo(size * 0.490654, size * 0.462616); + ptrCtx.lineTo(size * 0.481308, size * 0.471962); + ptrCtx.closePath(); + ptrCtx.fill(); + break; + + case 'type3': + ptrCtx.beginPath(); + ptrCtx.rect(size * 0.495327, size * 0.130841, size * 0.009345, size * 0.373831); + ptrCtx.closePath(); + ptrCtx.fillStyle = ptrColor.light.getRgbaColor(); + ptrCtx.fill(); + break; + + case 'type4': + grad = ptrCtx.createLinearGradient(0.467289 * size, 0, 0.528036 * size, 0); + grad.addColorStop(0, ptrColor.dark.getRgbaColor()); + grad.addColorStop(0.51, ptrColor.dark.getRgbaColor()); + grad.addColorStop(0.52, ptrColor.light.getRgbaColor()); + grad.addColorStop(1, ptrColor.light.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.5, size * 0.126168); + ptrCtx.lineTo(size * 0.514018, size * 0.135514); + ptrCtx.lineTo(size * 0.532710, size * 0.5); + ptrCtx.lineTo(size * 0.523364, size * 0.602803); + ptrCtx.lineTo(size * 0.476635, size * 0.602803); + ptrCtx.lineTo(size * 0.467289, size * 0.5); + ptrCtx.lineTo(size * 0.485981, size * 0.135514); + ptrCtx.lineTo(size * 0.5, size * 0.126168); + ptrCtx.closePath(); + ptrCtx.fill(); + break; + + case 'type5': + grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); + grad.addColorStop(0, ptrColor.light.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.medium.getRgbaColor()); grad.addColorStop(1, ptrColor.medium.getRgbaColor()); ptrCtx.fillStyle = grad; - } else { - // TYPE14 - grad = ptrCtx.createLinearGradient(0.485981 * size, 0, 0.509345 * size, 0); - grad.addColorStop(0, ptrColor.veryDark.getRgbaColor()); + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.5, size * 0.495327); + ptrCtx.lineTo(size * 0.528037, size * 0.495327); + ptrCtx.lineTo(size * 0.5, size * 0.149532); + ptrCtx.lineTo(size * 0.471962, size * 0.495327); + ptrCtx.lineTo(size * 0.5, size * 0.495327); + ptrCtx.closePath(); + ptrCtx.fill(); + + ptrCtx.lineWidth = 1; + ptrCtx.lineCap = 'square'; + ptrCtx.lineJoin = 'miter'; + ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); + ptrCtx.stroke(); + break; + + case 'type6': + ptrCtx.fillStyle = ptrColor.medium.getRgbaColor(); + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.481308, size * 0.485981); + ptrCtx.lineTo(size * 0.481308, size * 0.392523); + ptrCtx.lineTo(size * 0.485981, size * 0.317757); + ptrCtx.lineTo(size * 0.495327, size * 0.130841); + ptrCtx.lineTo(size * 0.504672, size * 0.130841); + ptrCtx.lineTo(size * 0.514018, size * 0.317757); + ptrCtx.lineTo(size * 0.518691, size * 0.387850); + ptrCtx.lineTo(size * 0.518691, size * 0.485981); + ptrCtx.lineTo(size * 0.504672, size * 0.485981); + ptrCtx.lineTo(size * 0.504672, size * 0.387850); + ptrCtx.lineTo(size * 0.5, size * 0.317757); + ptrCtx.lineTo(size * 0.495327, size * 0.392523); + ptrCtx.lineTo(size * 0.495327, size * 0.485981); + ptrCtx.lineTo(size * 0.481308, size * 0.485981); + ptrCtx.closePath(); + ptrCtx.fill(); + break; + + case 'type7': + grad = ptrCtx.createLinearGradient(0.481308 * size, 0, 0.518691 * size, 0); + grad.addColorStop(0, ptrColor.dark.getRgbaColor()); + grad.addColorStop(1, ptrColor.medium.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.490654, size * 0.130841); + ptrCtx.lineTo(size * 0.481308, size * 0.5); + ptrCtx.lineTo(size * 0.518691, size * 0.5); + ptrCtx.lineTo(size * 0.504672, size * 0.130841); + ptrCtx.lineTo(size * 0.490654, size * 0.130841); + ptrCtx.closePath(); + ptrCtx.fill(); + break; + + case 'type8': + grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); + grad.addColorStop(0, ptrColor.light.getRgbaColor()); grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.medium.getRgbaColor()); + grad.addColorStop(1, ptrColor.medium.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.5, size * 0.532710); + ptrCtx.lineTo(size * 0.532710, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.532710, size * 0.5, size * 0.509345, size * 0.457943, size * 0.5, size * 0.149532); + ptrCtx.bezierCurveTo(size * 0.490654, size * 0.457943, size * 0.467289, size * 0.5, size * 0.467289, size * 0.5); + ptrCtx.lineTo(size * 0.5, size * 0.532710); + ptrCtx.closePath(); + ptrCtx.fill(); + ptrCtx.stroke(); + break; + + case 'type9': + grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); + grad.addColorStop(0, 'rgb(50, 50, 50)'); + grad.addColorStop(0.5, '#666666'); + grad.addColorStop(1, 'rgb(50, 50, 50)'); + ptrCtx.fillStyle = grad; + ptrCtx.strokeStyle = '#2E2E2E'; + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.495327, size * 0.233644); + ptrCtx.lineTo(size * 0.504672, size * 0.233644); + ptrCtx.lineTo(size * 0.514018, size * 0.439252); + ptrCtx.lineTo(size * 0.485981, size * 0.439252); + ptrCtx.lineTo(size * 0.495327, size * 0.233644); + ptrCtx.closePath(); + ptrCtx.moveTo(size * 0.490654, size * 0.130841); + ptrCtx.lineTo(size * 0.471962, size * 0.471962); + ptrCtx.lineTo(size * 0.471962, size * 0.528037); + ptrCtx.bezierCurveTo(size * 0.471962, size * 0.528037, size * 0.476635, size * 0.602803, size * 0.476635, size * 0.602803); + ptrCtx.bezierCurveTo(size * 0.476635, size * 0.607476, size * 0.481308, size * 0.607476, size * 0.5, size * 0.607476); + ptrCtx.bezierCurveTo(size * 0.518691, size * 0.607476, size * 0.523364, size * 0.607476, size * 0.523364, size * 0.602803); + ptrCtx.bezierCurveTo(size * 0.523364, size * 0.602803, size * 0.528037, size * 0.528037, size * 0.528037, size * 0.528037); + ptrCtx.lineTo(size * 0.528037, size * 0.471962); + ptrCtx.lineTo(size * 0.509345, size * 0.130841); + ptrCtx.lineTo(size * 0.490654, size * 0.130841); + ptrCtx.closePath(); + ptrCtx.fill(); + + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.495327, size * 0.219626); + ptrCtx.lineTo(size * 0.504672, size * 0.219626); + ptrCtx.lineTo(size * 0.504672, size * 0.135514); + ptrCtx.lineTo(size * 0.495327, size * 0.135514); + ptrCtx.lineTo(size * 0.495327, size * 0.219626); + ptrCtx.closePath(); + + ptrCtx.fillStyle = ptrColor.medium.getRgbaColor(); + ptrCtx.fill(); + break; + + case 'type10': + // POINTER_TYPE10 + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.5, size * 0.149532); + ptrCtx.bezierCurveTo(size * 0.5, size * 0.149532, size * 0.443925, size * 0.490654, size * 0.443925, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.443925, size * 0.532710, size * 0.467289, size * 0.556074, size * 0.5, size * 0.556074); + ptrCtx.bezierCurveTo(size * 0.532710, size * 0.556074, size * 0.556074, size * 0.532710, size * 0.556074, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.556074, size * 0.490654, size * 0.5, size * 0.149532, size * 0.5, size * 0.149532); + ptrCtx.closePath(); + grad = ptrCtx.createLinearGradient(0.471962 * size, 0, 0.528036 * size, 0); + grad.addColorStop(0, ptrColor.light.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.medium.getRgbaColor()); + grad.addColorStop(1, ptrColor.medium.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.strokeStyle = ptrColor.medium.getRgbaColor(); + ptrCtx.lineWidth = 1; + ptrCtx.lineCap = 'square'; + ptrCtx.lineJoin = 'miter'; + ptrCtx.fill(); + ptrCtx.stroke(); + break; + + case 'type11': + // POINTER_TYPE11 + ptrCtx.beginPath(); + ptrCtx.moveTo(0.5 * size, 0.168224 * size); + ptrCtx.lineTo(0.485981 * size, 0.5 * size); + ptrCtx.bezierCurveTo(0.485981 * size, 0.5 * size, 0.481308 * size, 0.584112 * size, 0.5 * size, 0.584112 * size); + ptrCtx.bezierCurveTo(0.514018 * size, 0.584112 * size, 0.509345 * size, 0.5 * size, 0.509345 * size, 0.5 * size); + ptrCtx.lineTo(0.5 * size, 0.168224 * size); + ptrCtx.closePath(); + grad = ptrCtx.createLinearGradient(0, 0.168224 * size, 0, 0.584112 * size); + grad.addColorStop(0, ptrColor.medium.getRgbaColor()); + grad.addColorStop(1, ptrColor.dark.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); + ptrCtx.fill(); + ptrCtx.stroke(); + break; + + case 'type12': + // POINTER_TYPE12 + ptrCtx.beginPath(); + ptrCtx.moveTo(0.5 * size, 0.168224 * size); + ptrCtx.lineTo(0.485981 * size, 0.5 * size); + ptrCtx.lineTo(0.5 * size, 0.504672 * size); + ptrCtx.lineTo(0.509345 * size, 0.5 * size); + ptrCtx.lineTo(0.5 * size, 0.168224 * size); + ptrCtx.closePath(); + grad = ptrCtx.createLinearGradient(0, 0.168224 * size, 0, 0.504672 * size); + grad.addColorStop(0, ptrColor.medium.getRgbaColor()); + grad.addColorStop(1, ptrColor.dark.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); + ptrCtx.fill(); + ptrCtx.stroke(); + break; + + case 'type13': + // POINTER_TYPE13 + case 'type14': + // POINTER_TYPE14 (same shape as 13) + ptrCtx.beginPath(); + ptrCtx.moveTo(0.485981 * size, 0.168224 * size); + ptrCtx.lineTo(0.5 * size, 0.130841 * size); + ptrCtx.lineTo(0.509345 * size, 0.168224 * size); + ptrCtx.lineTo(0.509345 * size, 0.509345 * size); + ptrCtx.lineTo(0.485981 * size, 0.509345 * size); + ptrCtx.lineTo(0.485981 * size, 0.168224 * size); + ptrCtx.closePath(); + if (ptrType.type === 'type13') { + // TYPE13 + grad = ptrCtx.createLinearGradient(0, 0.5 * size, 0, 0.130841 * size); + grad.addColorStop(0, lblColor.getRgbaColor()); + grad.addColorStop(0.85, lblColor.getRgbaColor()); + grad.addColorStop(0.85, ptrColor.medium.getRgbaColor()); + grad.addColorStop(1, ptrColor.medium.getRgbaColor()); + ptrCtx.fillStyle = grad; + } else { + // TYPE14 + grad = ptrCtx.createLinearGradient(0.485981 * size, 0, 0.509345 * size, 0); + grad.addColorStop(0, ptrColor.veryDark.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); + grad.addColorStop(1, ptrColor.veryDark.getRgbaColor()); + ptrCtx.fillStyle = grad; + } + ptrCtx.fill(); + break; + + case 'type15': + // POINTER TYPE15 - Classic with crescent + case 'type16': + // POINTER TYPE16 - Classic without crescent + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.509345, size * 0.457943); + ptrCtx.lineTo(size * 0.5015, size * 0.13); + ptrCtx.lineTo(size * 0.4985, size * 0.13); + ptrCtx.lineTo(size * 0.490654, size * 0.457943); + ptrCtx.bezierCurveTo(size * 0.490654, size * 0.457943, size * 0.490654, size * 0.457943, size * 0.490654, size * 0.457943); + ptrCtx.bezierCurveTo(size * 0.471962, size * 0.462616, size * 0.457943, size * 0.481308, size * 0.457943, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.457943, size * 0.518691, size * 0.471962, size * 0.537383, size * 0.490654, size * 0.542056); + ptrCtx.bezierCurveTo(size * 0.490654, size * 0.542056, size * 0.490654, size * 0.542056, size * 0.490654, size * 0.542056); + if (ptrType.type === 'type15') { + ptrCtx.lineTo(size * 0.490654, size * 0.57); + ptrCtx.bezierCurveTo(size * 0.46, size * 0.58, size * 0.46, size * 0.62, size * 0.490654, size * 0.63); + ptrCtx.bezierCurveTo(size * 0.47, size * 0.62, size * 0.48, size * 0.59, size * 0.5, size * 0.59); + ptrCtx.bezierCurveTo(size * 0.53, size * 0.59, size * 0.52, size * 0.62, size * 0.509345, size * 0.63); + ptrCtx.bezierCurveTo(size * 0.54, size * 0.62, size * 0.54, size * 0.58, size * 0.509345, size * 0.57); + ptrCtx.lineTo(size * 0.509345, size * 0.57); + } else { + ptrCtx.lineTo(size * 0.490654, size * 0.621495); + ptrCtx.lineTo(size * 0.509345, size * 0.621495); + } + ptrCtx.lineTo(size * 0.509345, size * 0.542056); + ptrCtx.bezierCurveTo(size * 0.509345, size * 0.542056, size * 0.509345, size * 0.542056, size * 0.509345, size * 0.542056); + ptrCtx.bezierCurveTo(size * 0.528037, size * 0.537383, size * 0.542056, size * 0.518691, size * 0.542056, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.542056, size * 0.481308, size * 0.528037, size * 0.462616, size * 0.509345, size * 0.457943); + ptrCtx.bezierCurveTo(size * 0.509345, size * 0.457943, size * 0.509345, size * 0.457943, size * 0.509345, size * 0.457943); + ptrCtx.closePath(); + if (ptrType.type === 'type15') { + grad = ptrCtx.createLinearGradient(0, 0, 0, size * 0.63); + } else { + grad = ptrCtx.createLinearGradient(0, 0, 0, size * 0.621495); + } + grad.addColorStop(0, ptrColor.medium.getRgbaColor()); + grad.addColorStop(0.388888, ptrColor.medium.getRgbaColor()); + grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); + grad.addColorStop(0.611111, ptrColor.medium.getRgbaColor()); + grad.addColorStop(1, ptrColor.medium.getRgbaColor()); + ptrCtx.fillStyle = grad; + ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); + ptrCtx.fill(); + ptrCtx.stroke(); + // Draw the rings + ptrCtx.beginPath(); + radius = size * 0.065420 / 2; + ptrCtx.arc(size * 0.5, size * 0.5, radius, 0, TWO_PI); + grad = ptrCtx.createLinearGradient(size * 0.5 - radius, size * 0.5 + radius, 0, size * 0.5 + radius); + grad.addColorStop(0, '#e6b35c'); + grad.addColorStop(0.01, '#e6b35c'); + grad.addColorStop(0.99, '#c48200'); + grad.addColorStop(1, '#c48200'); + ptrCtx.fillStyle = grad; + ptrCtx.closePath(); + ptrCtx.fill(); + ptrCtx.beginPath(); + radius = size * 0.046728 / 2; + ptrCtx.arc(size * 0.5, size * 0.5, radius, 0, TWO_PI); + grad = ptrCtx.createRadialGradient(size * 0.5, size * 0.5, 0, size * 0.5, size * 0.5, radius); + grad.addColorStop(0, '#c5c5c5'); + grad.addColorStop(0.19, '#c5c5c5'); + grad.addColorStop(0.22, '#000000'); + grad.addColorStop(0.8, '#000000'); + grad.addColorStop(0.99, '#707070'); + grad.addColorStop(1, '#707070'); + ptrCtx.fillStyle = grad; + ptrCtx.closePath(); + ptrCtx.fill(); + break; + + case 'type1': + /* falls through */ + default: + grad = ptrCtx.createLinearGradient(0, size * 0.471962, 0, size * 0.130841); + grad.addColorStop(0, ptrColor.veryDark.getRgbaColor()); + grad.addColorStop(0.3, ptrColor.medium.getRgbaColor()); + grad.addColorStop(0.59, ptrColor.medium.getRgbaColor()); grad.addColorStop(1, ptrColor.veryDark.getRgbaColor()); ptrCtx.fillStyle = grad; - } - ptrCtx.fill(); - break; - - case 'type15': - // POINTER TYPE15 - Classic with crescent - case 'type16': - // POINTER TYPE16 - Classic without crescent - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.509345, size * 0.457943); - ptrCtx.lineTo(size * 0.5015, size * 0.13); - ptrCtx.lineTo(size * 0.4985, size * 0.13); - ptrCtx.lineTo(size * 0.490654, size * 0.457943); - ptrCtx.bezierCurveTo(size * 0.490654, size * 0.457943, size * 0.490654, size * 0.457943, size * 0.490654, size * 0.457943); - ptrCtx.bezierCurveTo(size * 0.471962, size * 0.462616, size * 0.457943, size * 0.481308, size * 0.457943, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.457943, size * 0.518691, size * 0.471962, size * 0.537383, size * 0.490654, size * 0.542056); - ptrCtx.bezierCurveTo(size * 0.490654, size * 0.542056, size * 0.490654, size * 0.542056, size * 0.490654, size * 0.542056); - if (ptrType.type === 'type15') { - ptrCtx.lineTo(size * 0.490654, size * 0.57); - ptrCtx.bezierCurveTo(size * 0.46, size * 0.58, size * 0.46, size * 0.62, size * 0.490654, size * 0.63); - ptrCtx.bezierCurveTo(size * 0.47, size * 0.62, size * 0.48, size * 0.59, size * 0.5, size * 0.59); - ptrCtx.bezierCurveTo(size * 0.53, size * 0.59, size * 0.52, size * 0.62, size * 0.509345, size * 0.63); - ptrCtx.bezierCurveTo(size * 0.54, size * 0.62, size * 0.54, size * 0.58, size * 0.509345, size * 0.57); - ptrCtx.lineTo(size * 0.509345, size * 0.57); - } else { - ptrCtx.lineTo(size * 0.490654, size * 0.621495); - ptrCtx.lineTo(size * 0.509345, size * 0.621495); - } - ptrCtx.lineTo(size * 0.509345, size * 0.542056); - ptrCtx.bezierCurveTo(size * 0.509345, size * 0.542056, size * 0.509345, size * 0.542056, size * 0.509345, size * 0.542056); - ptrCtx.bezierCurveTo(size * 0.528037, size * 0.537383, size * 0.542056, size * 0.518691, size * 0.542056, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.542056, size * 0.481308, size * 0.528037, size * 0.462616, size * 0.509345, size * 0.457943); - ptrCtx.bezierCurveTo(size * 0.509345, size * 0.457943, size * 0.509345, size * 0.457943, size * 0.509345, size * 0.457943); - ptrCtx.closePath(); - if (ptrType.type === 'type15') { - grad = ptrCtx.createLinearGradient(0, 0, 0, size * 0.63); - } else { - grad = ptrCtx.createLinearGradient(0, 0, 0, size * 0.621495); - } - grad.addColorStop(0, ptrColor.medium.getRgbaColor()); - grad.addColorStop(0.388888, ptrColor.medium.getRgbaColor()); - grad.addColorStop(0.5, ptrColor.light.getRgbaColor()); - grad.addColorStop(0.611111, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.medium.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.strokeStyle = ptrColor.dark.getRgbaColor(); - ptrCtx.fill(); - ptrCtx.stroke(); - // Draw the rings - ptrCtx.beginPath(); - radius = size * 0.065420 / 2; - ptrCtx.arc(size * 0.5, size * 0.5, radius, 0, TWO_PI); - grad = ptrCtx.createLinearGradient(size * 0.5 - radius, size * 0.5 + radius, 0, size * 0.5 + radius); - grad.addColorStop(0, '#e6b35c'); - grad.addColorStop(0.01, '#e6b35c'); - grad.addColorStop(0.99, '#c48200'); - grad.addColorStop(1, '#c48200'); - ptrCtx.fillStyle = grad; - ptrCtx.closePath(); - ptrCtx.fill(); - ptrCtx.beginPath(); - radius = size * 0.046728 / 2; - ptrCtx.arc(size * 0.5, size * 0.5, radius, 0, TWO_PI); - grad = ptrCtx.createRadialGradient(size * 0.5, size * 0.5, 0, size * 0.5, size * 0.5, radius); - grad.addColorStop(0, '#c5c5c5'); - grad.addColorStop(0.19, '#c5c5c5'); - grad.addColorStop(0.22, '#000000'); - grad.addColorStop(0.8, '#000000'); - grad.addColorStop(0.99, '#707070'); - grad.addColorStop(1, '#707070'); - ptrCtx.fillStyle = grad; - ptrCtx.closePath(); - ptrCtx.fill(); - break; - - case 'type1': - /* falls through */ - default: - grad = ptrCtx.createLinearGradient(0, size * 0.471962, 0, size * 0.130841); - grad.addColorStop(0, ptrColor.veryDark.getRgbaColor()); - grad.addColorStop(0.3, ptrColor.medium.getRgbaColor()); - grad.addColorStop(0.59, ptrColor.medium.getRgbaColor()); - grad.addColorStop(1, ptrColor.veryDark.getRgbaColor()); - ptrCtx.fillStyle = grad; - ptrCtx.beginPath(); - ptrCtx.moveTo(size * 0.518691, size * 0.471962); - ptrCtx.bezierCurveTo(size * 0.514018, size * 0.457943, size * 0.509345, size * 0.415887, size * 0.509345, size * 0.401869); - ptrCtx.bezierCurveTo(size * 0.504672, size * 0.383177, size * 0.5, size * 0.130841, size * 0.5, size * 0.130841); - ptrCtx.bezierCurveTo(size * 0.5, size * 0.130841, size * 0.490654, size * 0.383177, size * 0.490654, size * 0.397196); - ptrCtx.bezierCurveTo(size * 0.490654, size * 0.415887, size * 0.485981, size * 0.457943, size * 0.481308, size * 0.471962); - ptrCtx.bezierCurveTo(size * 0.471962, size * 0.481308, size * 0.467289, size * 0.490654, size * 0.467289, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.467289, size * 0.518691, size * 0.481308, size * 0.532710, size * 0.5, size * 0.532710); - ptrCtx.bezierCurveTo(size * 0.518691, size * 0.532710, size * 0.532710, size * 0.518691, size * 0.532710, size * 0.5); - ptrCtx.bezierCurveTo(size * 0.532710, size * 0.490654, size * 0.528037, size * 0.481308, size * 0.518691, size * 0.471962); - ptrCtx.closePath(); - ptrCtx.fill(); - break; + ptrCtx.beginPath(); + ptrCtx.moveTo(size * 0.518691, size * 0.471962); + ptrCtx.bezierCurveTo(size * 0.514018, size * 0.457943, size * 0.509345, size * 0.415887, size * 0.509345, size * 0.401869); + ptrCtx.bezierCurveTo(size * 0.504672, size * 0.383177, size * 0.5, size * 0.130841, size * 0.5, size * 0.130841); + ptrCtx.bezierCurveTo(size * 0.5, size * 0.130841, size * 0.490654, size * 0.383177, size * 0.490654, size * 0.397196); + ptrCtx.bezierCurveTo(size * 0.490654, size * 0.415887, size * 0.485981, size * 0.457943, size * 0.481308, size * 0.471962); + ptrCtx.bezierCurveTo(size * 0.471962, size * 0.481308, size * 0.467289, size * 0.490654, size * 0.467289, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.467289, size * 0.518691, size * 0.481308, size * 0.532710, size * 0.5, size * 0.532710); + ptrCtx.bezierCurveTo(size * 0.518691, size * 0.532710, size * 0.532710, size * 0.518691, size * 0.532710, size * 0.5); + ptrCtx.bezierCurveTo(size * 0.532710, size * 0.490654, size * 0.528037, size * 0.481308, size * 0.518691, size * 0.471962); + ptrCtx.closePath(); + ptrCtx.fill(); + break; } // cache buffer drawPointerImage.cache[cacheKey] = ptrBuffer; @@ -4496,255 +4530,255 @@ var steelseries = (function () { // main gradient frame switch (frameDesign.design) { - case 'metal': - grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); - grad.addColorStop(0, '#fefefe'); - grad.addColorStop(0.07, 'rgb(210, 210, 210)'); - grad.addColorStop(0.12, 'rgb(179, 179, 179)'); - grad.addColorStop(1, 'rgb(213, 213, 213)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'metal': + grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); + grad.addColorStop(0, '#fefefe'); + grad.addColorStop(0.07, 'rgb(210, 210, 210)'); + grad.addColorStop(0.12, 'rgb(179, 179, 179)'); + grad.addColorStop(1, 'rgb(213, 213, 213)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'brass': - grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); - grad.addColorStop(0, 'rgb(249, 243, 155)'); - grad.addColorStop(0.05, 'rgb(246, 226, 101)'); - grad.addColorStop(0.10, 'rgb(240, 225, 132)'); - grad.addColorStop(0.50, 'rgb(90, 57, 22)'); - grad.addColorStop(0.90, 'rgb(249, 237, 139)'); - grad.addColorStop(0.95, 'rgb(243, 226, 108)'); - grad.addColorStop(1, 'rgb(202, 182, 113)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'brass': + grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); + grad.addColorStop(0, 'rgb(249, 243, 155)'); + grad.addColorStop(0.05, 'rgb(246, 226, 101)'); + grad.addColorStop(0.10, 'rgb(240, 225, 132)'); + grad.addColorStop(0.50, 'rgb(90, 57, 22)'); + grad.addColorStop(0.90, 'rgb(249, 237, 139)'); + grad.addColorStop(0.95, 'rgb(243, 226, 108)'); + grad.addColorStop(1, 'rgb(202, 182, 113)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'steel': - grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); - grad.addColorStop(0, 'rgb(231, 237, 237)'); - grad.addColorStop(0.05, 'rgb(189, 199, 198)'); - grad.addColorStop(0.10, 'rgb(192, 201, 200)'); - grad.addColorStop(0.50, 'rgb(23, 31, 33)'); - grad.addColorStop(0.90, 'rgb(196, 205, 204)'); - grad.addColorStop(0.95, 'rgb(194, 204, 203)'); - grad.addColorStop(1, 'rgb(189, 201, 199)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'steel': + grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); + grad.addColorStop(0, 'rgb(231, 237, 237)'); + grad.addColorStop(0.05, 'rgb(189, 199, 198)'); + grad.addColorStop(0.10, 'rgb(192, 201, 200)'); + grad.addColorStop(0.50, 'rgb(23, 31, 33)'); + grad.addColorStop(0.90, 'rgb(196, 205, 204)'); + grad.addColorStop(0.95, 'rgb(194, 204, 203)'); + grad.addColorStop(1, 'rgb(189, 201, 199)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'gold': - grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); - grad.addColorStop(0, 'rgb(255, 255, 207)'); - grad.addColorStop(0.15, 'rgb(255, 237, 96)'); - grad.addColorStop(0.22, 'rgb(254, 199, 57)'); - grad.addColorStop(0.3, 'rgb(255, 249, 203)'); - grad.addColorStop(0.38, 'rgb(255, 199, 64)'); - grad.addColorStop(0.44, 'rgb(252, 194, 60)'); - grad.addColorStop(0.51, 'rgb(255, 204, 59)'); - grad.addColorStop(0.6, 'rgb(213, 134, 29)'); - grad.addColorStop(0.68, 'rgb(255, 201, 56)'); - grad.addColorStop(0.75, 'rgb(212, 135, 29)'); - grad.addColorStop(1, 'rgb(247, 238, 101)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'gold': + grad = radFCtx.createLinearGradient(0, imageWidth * 0.004672, 0, imageHeight * 0.990654); + grad.addColorStop(0, 'rgb(255, 255, 207)'); + grad.addColorStop(0.15, 'rgb(255, 237, 96)'); + grad.addColorStop(0.22, 'rgb(254, 199, 57)'); + grad.addColorStop(0.3, 'rgb(255, 249, 203)'); + grad.addColorStop(0.38, 'rgb(255, 199, 64)'); + grad.addColorStop(0.44, 'rgb(252, 194, 60)'); + grad.addColorStop(0.51, 'rgb(255, 204, 59)'); + grad.addColorStop(0.6, 'rgb(213, 134, 29)'); + grad.addColorStop(0.68, 'rgb(255, 201, 56)'); + grad.addColorStop(0.75, 'rgb(212, 135, 29)'); + grad.addColorStop(1, 'rgb(247, 238, 101)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'anthracite': - grad = radFCtx.createLinearGradient(0, 0.004672 * imageHeight, 0, 0.995326 * imageHeight); - grad.addColorStop(0, 'rgb(118, 117, 135)'); - grad.addColorStop(0.06, 'rgb(74, 74, 82)'); - grad.addColorStop(0.12, 'rgb(50, 50, 54)'); - grad.addColorStop(1, 'rgb(79, 79, 87)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'anthracite': + grad = radFCtx.createLinearGradient(0, 0.004672 * imageHeight, 0, 0.995326 * imageHeight); + grad.addColorStop(0, 'rgb(118, 117, 135)'); + grad.addColorStop(0.06, 'rgb(74, 74, 82)'); + grad.addColorStop(0.12, 'rgb(50, 50, 54)'); + grad.addColorStop(1, 'rgb(79, 79, 87)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'tiltedGray': - grad = radFCtx.createLinearGradient(0.233644 * imageWidth, 0.084112 * imageHeight, 0.81258 * imageWidth, 0.910919 * imageHeight); - grad.addColorStop(0, '#ffffff'); - grad.addColorStop(0.07, 'rgb(210, 210, 210)'); - grad.addColorStop(0.16, 'rgb(179, 179, 179)'); - grad.addColorStop(0.33, '#ffffff'); - grad.addColorStop(0.55, '#c5c5c5'); - grad.addColorStop(0.79, '#ffffff'); - grad.addColorStop(1, '#666666'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'tiltedGray': + grad = radFCtx.createLinearGradient(0.233644 * imageWidth, 0.084112 * imageHeight, 0.81258 * imageWidth, 0.910919 * imageHeight); + grad.addColorStop(0, '#ffffff'); + grad.addColorStop(0.07, 'rgb(210, 210, 210)'); + grad.addColorStop(0.16, 'rgb(179, 179, 179)'); + grad.addColorStop(0.33, '#ffffff'); + grad.addColorStop(0.55, '#c5c5c5'); + grad.addColorStop(0.79, '#ffffff'); + grad.addColorStop(1, '#666666'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'tiltedBlack': - grad = radFCtx.createLinearGradient(0.228971 * imageWidth, 0.079439 * imageHeight, 0.802547 * imageWidth, 0.898591 * imageHeight); - grad.addColorStop(0, '#666666'); - grad.addColorStop(0.21, '#000000'); - grad.addColorStop(0.47, '#666666'); - grad.addColorStop(0.99, '#000000'); - grad.addColorStop(1, '#000000'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - break; + case 'tiltedBlack': + grad = radFCtx.createLinearGradient(0.228971 * imageWidth, 0.079439 * imageHeight, 0.802547 * imageWidth, 0.898591 * imageHeight); + grad.addColorStop(0, '#666666'); + grad.addColorStop(0.21, '#000000'); + grad.addColorStop(0.47, '#666666'); + grad.addColorStop(0.99, '#000000'); + grad.addColorStop(1, '#000000'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + break; - case 'glossyMetal': - grad = radFCtx.createRadialGradient(0.5 * imageWidth, 0.5 * imageHeight, 0, 0.5 * imageWidth, 0.5 * imageWidth, 0.5 * imageWidth); - grad.addColorStop(0, 'rgb(207, 207, 207)'); - grad.addColorStop(0.96, 'rgb(205, 204, 205)'); - grad.addColorStop(1, 'rgb(244, 244, 244)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); - radFCtx.beginPath(); - radFCtx.arc(0.5 * imageWidth, 0.5 * imageHeight, 0.973962 * imageWidth / 2, 0, TWO_PI); - radFCtx.closePath(); - grad = radFCtx.createLinearGradient(0, imageHeight - 0.971962 * imageHeight, 0, 0.971962 * imageHeight); - grad.addColorStop(0, 'rgb(249, 249, 249)'); - grad.addColorStop(0.23, 'rgb(200, 195, 191)'); - grad.addColorStop(0.36, '#ffffff'); - grad.addColorStop(0.59, 'rgb(29, 29, 29)'); - grad.addColorStop(0.76, 'rgb(200, 194, 192)'); - grad.addColorStop(1, 'rgb(209, 209, 209)'); - radFCtx.fillStyle = grad; - radFCtx.fill(); + case 'glossyMetal': + grad = radFCtx.createRadialGradient(0.5 * imageWidth, 0.5 * imageHeight, 0, 0.5 * imageWidth, 0.5 * imageWidth, 0.5 * imageWidth); + grad.addColorStop(0, 'rgb(207, 207, 207)'); + grad.addColorStop(0.96, 'rgb(205, 204, 205)'); + grad.addColorStop(1, 'rgb(244, 244, 244)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); + radFCtx.beginPath(); + radFCtx.arc(0.5 * imageWidth, 0.5 * imageHeight, 0.973962 * imageWidth / 2, 0, TWO_PI); + radFCtx.closePath(); + grad = radFCtx.createLinearGradient(0, imageHeight - 0.971962 * imageHeight, 0, 0.971962 * imageHeight); + grad.addColorStop(0, 'rgb(249, 249, 249)'); + grad.addColorStop(0.23, 'rgb(200, 195, 191)'); + grad.addColorStop(0.36, '#ffffff'); + grad.addColorStop(0.59, 'rgb(29, 29, 29)'); + grad.addColorStop(0.76, 'rgb(200, 194, 192)'); + grad.addColorStop(1, 'rgb(209, 209, 209)'); + radFCtx.fillStyle = grad; + radFCtx.fill(); - radFCtx.beginPath(); - radFCtx.arc(0.5 * imageWidth, 0.5 * imageHeight, 0.869158 * imageWidth / 2, 0, TWO_PI); - radFCtx.closePath(); - radFCtx.fillStyle = '#f6f6f6'; - radFCtx.fill(); + radFCtx.beginPath(); + radFCtx.arc(0.5 * imageWidth, 0.5 * imageHeight, 0.869158 * imageWidth / 2, 0, TWO_PI); + radFCtx.closePath(); + radFCtx.fillStyle = '#f6f6f6'; + radFCtx.fill(); - radFCtx.beginPath(); - radFCtx.arc(0.5 * imageWidth, 0.5 * imageHeight, 0.85 * imageWidth / 2, 0, TWO_PI); - radFCtx.closePath(); - radFCtx.fillStyle = '#333333'; - radFCtx.fill(); - break; + radFCtx.beginPath(); + radFCtx.arc(0.5 * imageWidth, 0.5 * imageHeight, 0.85 * imageWidth / 2, 0, TWO_PI); + radFCtx.closePath(); + radFCtx.fillStyle = '#333333'; + radFCtx.fill(); + break; - case 'blackMetal': - fractions = [0, - 0.125, - 0.347222, - 0.5, - 0.680555, - 0.875, - 1]; + case 'blackMetal': + fractions = [0, + 0.125, + 0.347222, + 0.5, + 0.680555, + 0.875, + 1]; - colors = [ new RgbaColor(254, 254, 254, 1), - new RgbaColor(0, 0, 0, 1), - new RgbaColor(153, 153, 153, 1), - new RgbaColor(0, 0, 0, 1), - new RgbaColor(153, 153, 153, 1), - new RgbaColor(0, 0, 0, 1), - new RgbaColor(254, 254, 254, 1)]; + colors = [new RgbaColor(254, 254, 254, 1), + new RgbaColor(0, 0, 0, 1), + new RgbaColor(153, 153, 153, 1), + new RgbaColor(0, 0, 0, 1), + new RgbaColor(153, 153, 153, 1), + new RgbaColor(0, 0, 0, 1), + new RgbaColor(254, 254, 254, 1)]; - radFCtx.save(); - radFCtx.arc(centerX, centerY, imageWidth * 0.990654 / 2, 0, TWO_PI, true); - radFCtx.clip(); - outerX = imageWidth * 0.495327; - innerX = imageWidth * 0.420560; - grad = new ConicalGradient(fractions, colors); - grad.fillCircle(radFCtx, centerX, centerY, innerX, outerX); - // fade outer edge - radFCtx.strokeStyle = '#848484'; - radFCtx.strokeStyle = 'rgba(132, 132, 132, 0.8)'; - radFCtx.beginPath(); - radFCtx.lineWidth = imageWidth / 90; - radFCtx.arc(centerX, centerY, imageWidth / 2, 0, TWO_PI, true); - radFCtx.closePath(); - radFCtx.stroke(); - radFCtx.restore(); - break; + radFCtx.save(); + radFCtx.arc(centerX, centerY, imageWidth * 0.990654 / 2, 0, TWO_PI, true); + radFCtx.clip(); + outerX = imageWidth * 0.495327; + innerX = imageWidth * 0.420560; + grad = new ConicalGradient(fractions, colors); + grad.fillCircle(radFCtx, centerX, centerY, innerX, outerX); + // fade outer edge + radFCtx.strokeStyle = '#848484'; + radFCtx.strokeStyle = 'rgba(132, 132, 132, 0.8)'; + radFCtx.beginPath(); + radFCtx.lineWidth = imageWidth / 90; + radFCtx.arc(centerX, centerY, imageWidth / 2, 0, TWO_PI, true); + radFCtx.closePath(); + radFCtx.stroke(); + radFCtx.restore(); + break; - case 'shinyMetal': - fractions = [0, - 0.125, - 0.25, - 0.347222, - 0.5, - 0.652777, - 0.75, - 0.875, - 1]; + case 'shinyMetal': + fractions = [0, + 0.125, + 0.25, + 0.347222, + 0.5, + 0.652777, + 0.75, + 0.875, + 1]; - colors = [ new RgbaColor(254, 254, 254, 1), - new RgbaColor(210, 210, 210, 1), - new RgbaColor(179, 179, 179, 1), - new RgbaColor(238, 238, 238, 1), - new RgbaColor(160, 160, 160, 1), - new RgbaColor(238, 238, 238, 1), - new RgbaColor(179, 179, 179, 1), - new RgbaColor(210, 210, 210, 1), - new RgbaColor(254, 254, 254, 1)]; + colors = [new RgbaColor(254, 254, 254, 1), + new RgbaColor(210, 210, 210, 1), + new RgbaColor(179, 179, 179, 1), + new RgbaColor(238, 238, 238, 1), + new RgbaColor(160, 160, 160, 1), + new RgbaColor(238, 238, 238, 1), + new RgbaColor(179, 179, 179, 1), + new RgbaColor(210, 210, 210, 1), + new RgbaColor(254, 254, 254, 1)]; - radFCtx.save(); - radFCtx.arc(centerX, centerY, imageWidth * 0.990654 / 2, 0, TWO_PI, true); - radFCtx.clip(); - outerX = imageWidth * 0.495327; - innerX = imageWidth * 0.420560; - grad = new ConicalGradient(fractions, colors); - grad.fillCircle(radFCtx, centerX, centerY, innerX, outerX); - // fade outer edge - radFCtx.strokeStyle = '#848484'; - radFCtx.strokeStyle = 'rgba(132, 132, 132, 0.8)'; - radFCtx.beginPath(); - radFCtx.lineWidth = imageWidth / 90; - radFCtx.arc(centerX, centerY, imageWidth / 2, 0, TWO_PI, true); - radFCtx.closePath(); - radFCtx.stroke(); - radFCtx.restore(); - break; + radFCtx.save(); + radFCtx.arc(centerX, centerY, imageWidth * 0.990654 / 2, 0, TWO_PI, true); + radFCtx.clip(); + outerX = imageWidth * 0.495327; + innerX = imageWidth * 0.420560; + grad = new ConicalGradient(fractions, colors); + grad.fillCircle(radFCtx, centerX, centerY, innerX, outerX); + // fade outer edge + radFCtx.strokeStyle = '#848484'; + radFCtx.strokeStyle = 'rgba(132, 132, 132, 0.8)'; + radFCtx.beginPath(); + radFCtx.lineWidth = imageWidth / 90; + radFCtx.arc(centerX, centerY, imageWidth / 2, 0, TWO_PI, true); + radFCtx.closePath(); + radFCtx.stroke(); + radFCtx.restore(); + break; - case 'chrome': - fractions = [0, - 0.09, - 0.12, - 0.16, - 0.25, - 0.29, - 0.33, - 0.38, - 0.48, - 0.52, - 0.63, - 0.68, - 0.8, - 0.83, - 0.87, - 0.97, - 1]; + case 'chrome': + fractions = [0, + 0.09, + 0.12, + 0.16, + 0.25, + 0.29, + 0.33, + 0.38, + 0.48, + 0.52, + 0.63, + 0.68, + 0.8, + 0.83, + 0.87, + 0.97, + 1]; - colors = [ new RgbaColor(255, 255, 255, 1), - new RgbaColor(255, 255, 255, 1), - new RgbaColor(136, 136, 138, 1), - new RgbaColor(164, 185, 190, 1), - new RgbaColor(158, 179, 182, 1), - new RgbaColor(112, 112, 112, 1), - new RgbaColor(221, 227, 227, 1), - new RgbaColor(155, 176, 179, 1), - new RgbaColor(156, 176, 177, 1), - new RgbaColor(254, 255, 255, 1), - new RgbaColor(255, 255, 255, 1), - new RgbaColor(156, 180, 180, 1), - new RgbaColor(198, 209, 211, 1), - new RgbaColor(246, 248, 247, 1), - new RgbaColor(204, 216, 216, 1), - new RgbaColor(164, 188, 190, 1), - new RgbaColor(255, 255, 255, 1)]; + colors = [new RgbaColor(255, 255, 255, 1), + new RgbaColor(255, 255, 255, 1), + new RgbaColor(136, 136, 138, 1), + new RgbaColor(164, 185, 190, 1), + new RgbaColor(158, 179, 182, 1), + new RgbaColor(112, 112, 112, 1), + new RgbaColor(221, 227, 227, 1), + new RgbaColor(155, 176, 179, 1), + new RgbaColor(156, 176, 177, 1), + new RgbaColor(254, 255, 255, 1), + new RgbaColor(255, 255, 255, 1), + new RgbaColor(156, 180, 180, 1), + new RgbaColor(198, 209, 211, 1), + new RgbaColor(246, 248, 247, 1), + new RgbaColor(204, 216, 216, 1), + new RgbaColor(164, 188, 190, 1), + new RgbaColor(255, 255, 255, 1)]; - radFCtx.save(); - radFCtx.arc(centerX, centerY, imageWidth * 0.990654 / 2, 0, TWO_PI, true); - radFCtx.clip(); - outerX = imageWidth * 0.495327; - innerX = imageWidth * 0.420560; - grad = new ConicalGradient(fractions, colors); - grad.fillCircle(radFCtx, centerX, centerY, innerX, outerX); - // fade outer edge - radFCtx.strokeStyle = '#848484'; - radFCtx.strokeStyle = 'rgba(132, 132, 132, 0.8)'; - radFCtx.beginPath(); - radFCtx.lineWidth = imageWidth / 90; - radFCtx.arc(centerX, centerY, imageWidth / 2, 0, TWO_PI, true); - radFCtx.closePath(); - radFCtx.stroke(); - radFCtx.restore(); + radFCtx.save(); + radFCtx.arc(centerX, centerY, imageWidth * 0.990654 / 2, 0, TWO_PI, true); + radFCtx.clip(); + outerX = imageWidth * 0.495327; + innerX = imageWidth * 0.420560; + grad = new ConicalGradient(fractions, colors); + grad.fillCircle(radFCtx, centerX, centerY, innerX, outerX); + // fade outer edge + radFCtx.strokeStyle = '#848484'; + radFCtx.strokeStyle = 'rgba(132, 132, 132, 0.8)'; + radFCtx.beginPath(); + radFCtx.lineWidth = imageWidth / 90; + radFCtx.arc(centerX, centerY, imageWidth / 2, 0, TWO_PI, true); + radFCtx.closePath(); + radFCtx.stroke(); + radFCtx.restore(); - break; + break; } // inner bright frame @@ -4825,37 +4859,37 @@ var steelseries = (function () { } else if (backgroundColor.name === 'STAINLESS' || backgroundColor.name === 'TURNED') { // Define the fractions of the conical gradient paint fractions = [0, - 0.03, - 0.10, - 0.14, - 0.24, - 0.33, - 0.38, - 0.5, - 0.62, - 0.67, - 0.76, - 0.81, - 0.85, - 0.97, - 1]; + 0.03, + 0.10, + 0.14, + 0.24, + 0.33, + 0.38, + 0.5, + 0.62, + 0.67, + 0.76, + 0.81, + 0.85, + 0.97, + 1]; // Define the colors of the conical gradient paint colors = [new RgbaColor('#FDFDFD'), - new RgbaColor('#FDFDFD'), - new RgbaColor('#B2B2B4'), - new RgbaColor('#ACACAE'), - new RgbaColor('#FDFDFD'), - new RgbaColor('#8E8E8E'), - new RgbaColor('#8E8E8E'), - new RgbaColor('#FDFDFD'), - new RgbaColor('#8E8E8E'), - new RgbaColor('#8E8E8E'), - new RgbaColor('#FDFDFD'), - new RgbaColor('#ACACAE'), - new RgbaColor('#B2B2B4'), - new RgbaColor('#FDFDFD'), - new RgbaColor('#FDFDFD')]; + new RgbaColor('#FDFDFD'), + new RgbaColor('#B2B2B4'), + new RgbaColor('#ACACAE'), + new RgbaColor('#FDFDFD'), + new RgbaColor('#8E8E8E'), + new RgbaColor('#8E8E8E'), + new RgbaColor('#FDFDFD'), + new RgbaColor('#8E8E8E'), + new RgbaColor('#8E8E8E'), + new RgbaColor('#FDFDFD'), + new RgbaColor('#ACACAE'), + new RgbaColor('#B2B2B4'), + new RgbaColor('#FDFDFD'), + new RgbaColor('#FDFDFD')]; grad = new ConicalGradient(fractions, colors); grad.fillCircle(radBCtx, centerX, centerY, 0, backgroundOffsetX); @@ -4877,7 +4911,7 @@ var steelseries = (function () { radBCtx.lineWidth = 0.5; end = TWO_PI - stepSize * 0.3; // Step the engine round'n'round - for (i = 0 ; i < end; i += stepSize) { + for (i = 0; i < end; i += stepSize) { // draw a 'turn' radBCtx.strokeStyle = 'rgba(240, 240, 255, 0.25)'; radBCtx.beginPath(); @@ -4959,7 +4993,7 @@ var steelseries = (function () { shadowOffset = imageWidth * 0.008, gradHighlight, gradHighlight2, cacheKey = foregroundType.type + imageWidth + imageHeight + withCenterKnob + (knob !== undefined ? knob.type : '-') + - (style !== undefined ? style.style : '-') + (orientation !== undefined ? orientation.type : '-'); + (style !== undefined ? style.style : '-') + (orientation !== undefined ? orientation.type : '-'); // check if we have already created and cached this buffer, if so return it and exit if (!drawRadialForegroundImage.cache[cacheKey]) { @@ -4995,97 +5029,97 @@ var steelseries = (function () { // highlight switch (foregroundType.type) { - case 'type2': - radFgCtx.beginPath(); - radFgCtx.moveTo(imageWidth * 0.135514, imageHeight * 0.696261); - radFgCtx.bezierCurveTo(imageWidth * 0.214953, imageHeight * 0.588785, imageWidth * 0.317757, imageHeight * 0.5, imageWidth * 0.462616, imageHeight * 0.425233); - radFgCtx.bezierCurveTo(imageWidth * 0.612149, imageHeight * 0.345794, imageWidth * 0.733644, imageHeight * 0.317757, imageWidth * 0.873831, imageHeight * 0.322429); - radFgCtx.bezierCurveTo(imageWidth * 0.766355, imageHeight * 0.112149, imageWidth * 0.528037, imageHeight * 0.023364, imageWidth * 0.313084, imageHeight * 0.130841); - radFgCtx.bezierCurveTo(imageWidth * 0.098130, imageHeight * 0.238317, imageWidth * 0.028037, imageHeight * 0.485981, imageWidth * 0.135514, imageHeight * 0.696261); - radFgCtx.closePath(); - gradHighlight = radFgCtx.createLinearGradient(0.313084 * imageWidth, 0.135514 * imageHeight, 0.495528 * imageWidth, 0.493582 * imageHeight); - gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); - gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); - break; + case 'type2': + radFgCtx.beginPath(); + radFgCtx.moveTo(imageWidth * 0.135514, imageHeight * 0.696261); + radFgCtx.bezierCurveTo(imageWidth * 0.214953, imageHeight * 0.588785, imageWidth * 0.317757, imageHeight * 0.5, imageWidth * 0.462616, imageHeight * 0.425233); + radFgCtx.bezierCurveTo(imageWidth * 0.612149, imageHeight * 0.345794, imageWidth * 0.733644, imageHeight * 0.317757, imageWidth * 0.873831, imageHeight * 0.322429); + radFgCtx.bezierCurveTo(imageWidth * 0.766355, imageHeight * 0.112149, imageWidth * 0.528037, imageHeight * 0.023364, imageWidth * 0.313084, imageHeight * 0.130841); + radFgCtx.bezierCurveTo(imageWidth * 0.098130, imageHeight * 0.238317, imageWidth * 0.028037, imageHeight * 0.485981, imageWidth * 0.135514, imageHeight * 0.696261); + radFgCtx.closePath(); + gradHighlight = radFgCtx.createLinearGradient(0.313084 * imageWidth, 0.135514 * imageHeight, 0.495528 * imageWidth, 0.493582 * imageHeight); + gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); + gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); + break; - case 'type3': - radFgCtx.beginPath(); - radFgCtx.moveTo(imageWidth * 0.084112, imageHeight * 0.509345); - radFgCtx.bezierCurveTo(imageWidth * 0.210280, imageHeight * 0.556074, imageWidth * 0.462616, imageHeight * 0.560747, imageWidth * 0.5, imageHeight * 0.560747); - radFgCtx.bezierCurveTo(imageWidth * 0.537383, imageHeight * 0.560747, imageWidth * 0.794392, imageHeight * 0.560747, imageWidth * 0.915887, imageHeight * 0.509345); - radFgCtx.bezierCurveTo(imageWidth * 0.915887, imageHeight * 0.275700, imageWidth * 0.738317, imageHeight * 0.084112, imageWidth * 0.5, imageHeight * 0.084112); - radFgCtx.bezierCurveTo(imageWidth * 0.261682, imageHeight * 0.084112, imageWidth * 0.084112, imageHeight * 0.275700, imageWidth * 0.084112, imageHeight * 0.509345); - radFgCtx.closePath(); - gradHighlight = radFgCtx.createLinearGradient(0, 0.093457 * imageHeight, 0, 0.556073 * imageHeight); - gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); - gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); - break; + case 'type3': + radFgCtx.beginPath(); + radFgCtx.moveTo(imageWidth * 0.084112, imageHeight * 0.509345); + radFgCtx.bezierCurveTo(imageWidth * 0.210280, imageHeight * 0.556074, imageWidth * 0.462616, imageHeight * 0.560747, imageWidth * 0.5, imageHeight * 0.560747); + radFgCtx.bezierCurveTo(imageWidth * 0.537383, imageHeight * 0.560747, imageWidth * 0.794392, imageHeight * 0.560747, imageWidth * 0.915887, imageHeight * 0.509345); + radFgCtx.bezierCurveTo(imageWidth * 0.915887, imageHeight * 0.275700, imageWidth * 0.738317, imageHeight * 0.084112, imageWidth * 0.5, imageHeight * 0.084112); + radFgCtx.bezierCurveTo(imageWidth * 0.261682, imageHeight * 0.084112, imageWidth * 0.084112, imageHeight * 0.275700, imageWidth * 0.084112, imageHeight * 0.509345); + radFgCtx.closePath(); + gradHighlight = radFgCtx.createLinearGradient(0, 0.093457 * imageHeight, 0, 0.556073 * imageHeight); + gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); + gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); + break; - case 'type4': - radFgCtx.beginPath(); - radFgCtx.moveTo(imageWidth * 0.677570, imageHeight * 0.242990); - radFgCtx.bezierCurveTo(imageWidth * 0.771028, imageHeight * 0.308411, imageWidth * 0.822429, imageHeight * 0.411214, imageWidth * 0.813084, imageHeight * 0.528037); - radFgCtx.bezierCurveTo(imageWidth * 0.799065, imageHeight * 0.654205, imageWidth * 0.719626, imageHeight * 0.757009, imageWidth * 0.593457, imageHeight * 0.799065); - radFgCtx.bezierCurveTo(imageWidth * 0.485981, imageHeight * 0.831775, imageWidth * 0.369158, imageHeight * 0.808411, imageWidth * 0.285046, imageHeight * 0.728971); - radFgCtx.bezierCurveTo(imageWidth * 0.275700, imageHeight * 0.719626, imageWidth * 0.252336, imageHeight * 0.714953, imageWidth * 0.233644, imageHeight * 0.728971); - radFgCtx.bezierCurveTo(imageWidth * 0.214953, imageHeight * 0.747663, imageWidth * 0.219626, imageHeight * 0.771028, imageWidth * 0.228971, imageHeight * 0.775700); - radFgCtx.bezierCurveTo(imageWidth * 0.331775, imageHeight * 0.878504, imageWidth * 0.476635, imageHeight * 0.915887, imageWidth * 0.616822, imageHeight * 0.869158); - radFgCtx.bezierCurveTo(imageWidth * 0.771028, imageHeight * 0.822429, imageWidth * 0.873831, imageHeight * 0.691588, imageWidth * 0.887850, imageHeight * 0.532710); - radFgCtx.bezierCurveTo(imageWidth * 0.897196, imageHeight * 0.387850, imageWidth * 0.836448, imageHeight * 0.257009, imageWidth * 0.719626, imageHeight * 0.182242); - radFgCtx.bezierCurveTo(imageWidth * 0.705607, imageHeight * 0.172897, imageWidth * 0.682242, imageHeight * 0.163551, imageWidth * 0.663551, imageHeight * 0.186915); - radFgCtx.bezierCurveTo(imageWidth * 0.654205, imageHeight * 0.205607, imageWidth * 0.668224, imageHeight * 0.238317, imageWidth * 0.677570, imageHeight * 0.242990); - radFgCtx.closePath(); - gradHighlight = radFgCtx.createRadialGradient((0.5) * imageWidth, ((0.5) * imageHeight), 0, ((0.5) * imageWidth), ((0.5) * imageHeight), 0.387850 * imageWidth); - gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0)'); - gradHighlight.addColorStop(0.82, 'rgba(255, 255, 255, 0)'); - gradHighlight.addColorStop(0.83, 'rgba(255, 255, 255, 0)'); - gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.15)'); + case 'type4': + radFgCtx.beginPath(); + radFgCtx.moveTo(imageWidth * 0.677570, imageHeight * 0.242990); + radFgCtx.bezierCurveTo(imageWidth * 0.771028, imageHeight * 0.308411, imageWidth * 0.822429, imageHeight * 0.411214, imageWidth * 0.813084, imageHeight * 0.528037); + radFgCtx.bezierCurveTo(imageWidth * 0.799065, imageHeight * 0.654205, imageWidth * 0.719626, imageHeight * 0.757009, imageWidth * 0.593457, imageHeight * 0.799065); + radFgCtx.bezierCurveTo(imageWidth * 0.485981, imageHeight * 0.831775, imageWidth * 0.369158, imageHeight * 0.808411, imageWidth * 0.285046, imageHeight * 0.728971); + radFgCtx.bezierCurveTo(imageWidth * 0.275700, imageHeight * 0.719626, imageWidth * 0.252336, imageHeight * 0.714953, imageWidth * 0.233644, imageHeight * 0.728971); + radFgCtx.bezierCurveTo(imageWidth * 0.214953, imageHeight * 0.747663, imageWidth * 0.219626, imageHeight * 0.771028, imageWidth * 0.228971, imageHeight * 0.775700); + radFgCtx.bezierCurveTo(imageWidth * 0.331775, imageHeight * 0.878504, imageWidth * 0.476635, imageHeight * 0.915887, imageWidth * 0.616822, imageHeight * 0.869158); + radFgCtx.bezierCurveTo(imageWidth * 0.771028, imageHeight * 0.822429, imageWidth * 0.873831, imageHeight * 0.691588, imageWidth * 0.887850, imageHeight * 0.532710); + radFgCtx.bezierCurveTo(imageWidth * 0.897196, imageHeight * 0.387850, imageWidth * 0.836448, imageHeight * 0.257009, imageWidth * 0.719626, imageHeight * 0.182242); + radFgCtx.bezierCurveTo(imageWidth * 0.705607, imageHeight * 0.172897, imageWidth * 0.682242, imageHeight * 0.163551, imageWidth * 0.663551, imageHeight * 0.186915); + radFgCtx.bezierCurveTo(imageWidth * 0.654205, imageHeight * 0.205607, imageWidth * 0.668224, imageHeight * 0.238317, imageWidth * 0.677570, imageHeight * 0.242990); + radFgCtx.closePath(); + gradHighlight = radFgCtx.createRadialGradient((0.5) * imageWidth, ((0.5) * imageHeight), 0, ((0.5) * imageWidth), ((0.5) * imageHeight), 0.387850 * imageWidth); + gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0)'); + gradHighlight.addColorStop(0.82, 'rgba(255, 255, 255, 0)'); + gradHighlight.addColorStop(0.83, 'rgba(255, 255, 255, 0)'); + gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.15)'); - radFgCtx.beginPath(); - radFgCtx.moveTo(imageWidth * 0.261682, imageHeight * 0.224299); - radFgCtx.bezierCurveTo(imageWidth * 0.285046, imageHeight * 0.238317, imageWidth * 0.252336, imageHeight * 0.285046, imageWidth * 0.242990, imageHeight * 0.317757); - radFgCtx.bezierCurveTo(imageWidth * 0.242990, imageHeight * 0.350467, imageWidth * 0.271028, imageHeight * 0.383177, imageWidth * 0.271028, imageHeight * 0.397196); - radFgCtx.bezierCurveTo(imageWidth * 0.275700, imageHeight * 0.415887, imageWidth * 0.261682, imageHeight * 0.457943, imageWidth * 0.238317, imageHeight * 0.509345); - radFgCtx.bezierCurveTo(imageWidth * 0.224299, imageHeight * 0.542056, imageWidth * 0.177570, imageHeight * 0.612149, imageWidth * 0.158878, imageHeight * 0.612149); - radFgCtx.bezierCurveTo(imageWidth * 0.144859, imageHeight * 0.612149, imageWidth * 0.088785, imageHeight * 0.546728, imageWidth * 0.130841, imageHeight * 0.369158); - radFgCtx.bezierCurveTo(imageWidth * 0.140186, imageHeight * 0.336448, imageWidth * 0.214953, imageHeight * 0.200934, imageWidth * 0.261682, imageHeight * 0.224299); - radFgCtx.closePath(); - gradHighlight2 = radFgCtx.createLinearGradient(0.130841 * imageWidth, 0.369158 * imageHeight, 0.273839 * imageWidth, 0.412877 * imageHeight); - gradHighlight2.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); - gradHighlight2.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); - radFgCtx.fillStyle = gradHighlight2; - radFgCtx.fill(); - break; + radFgCtx.beginPath(); + radFgCtx.moveTo(imageWidth * 0.261682, imageHeight * 0.224299); + radFgCtx.bezierCurveTo(imageWidth * 0.285046, imageHeight * 0.238317, imageWidth * 0.252336, imageHeight * 0.285046, imageWidth * 0.242990, imageHeight * 0.317757); + radFgCtx.bezierCurveTo(imageWidth * 0.242990, imageHeight * 0.350467, imageWidth * 0.271028, imageHeight * 0.383177, imageWidth * 0.271028, imageHeight * 0.397196); + radFgCtx.bezierCurveTo(imageWidth * 0.275700, imageHeight * 0.415887, imageWidth * 0.261682, imageHeight * 0.457943, imageWidth * 0.238317, imageHeight * 0.509345); + radFgCtx.bezierCurveTo(imageWidth * 0.224299, imageHeight * 0.542056, imageWidth * 0.177570, imageHeight * 0.612149, imageWidth * 0.158878, imageHeight * 0.612149); + radFgCtx.bezierCurveTo(imageWidth * 0.144859, imageHeight * 0.612149, imageWidth * 0.088785, imageHeight * 0.546728, imageWidth * 0.130841, imageHeight * 0.369158); + radFgCtx.bezierCurveTo(imageWidth * 0.140186, imageHeight * 0.336448, imageWidth * 0.214953, imageHeight * 0.200934, imageWidth * 0.261682, imageHeight * 0.224299); + radFgCtx.closePath(); + gradHighlight2 = radFgCtx.createLinearGradient(0.130841 * imageWidth, 0.369158 * imageHeight, 0.273839 * imageWidth, 0.412877 * imageHeight); + gradHighlight2.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); + gradHighlight2.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); + radFgCtx.fillStyle = gradHighlight2; + radFgCtx.fill(); + break; - case 'type5': - radFgCtx.beginPath(); - radFgCtx.moveTo(imageWidth * 0.084112, imageHeight * 0.5); - radFgCtx.bezierCurveTo(imageWidth * 0.084112, imageHeight * 0.271028, imageWidth * 0.271028, imageHeight * 0.084112, imageWidth * 0.5, imageHeight * 0.084112); - radFgCtx.bezierCurveTo(imageWidth * 0.700934, imageHeight * 0.084112, imageWidth * 0.864485, imageHeight * 0.224299, imageWidth * 0.906542, imageHeight * 0.411214); - radFgCtx.bezierCurveTo(imageWidth * 0.911214, imageHeight * 0.439252, imageWidth * 0.911214, imageHeight * 0.518691, imageWidth * 0.845794, imageHeight * 0.537383); - radFgCtx.bezierCurveTo(imageWidth * 0.794392, imageHeight * 0.546728, imageWidth * 0.551401, imageHeight * 0.411214, imageWidth * 0.392523, imageHeight * 0.457943); - radFgCtx.bezierCurveTo(imageWidth * 0.168224, imageHeight * 0.509345, imageWidth * 0.135514, imageHeight * 0.775700, imageWidth * 0.093457, imageHeight * 0.593457); - radFgCtx.bezierCurveTo(imageWidth * 0.088785, imageHeight * 0.560747, imageWidth * 0.084112, imageHeight * 0.532710, imageWidth * 0.084112, imageHeight * 0.5); - radFgCtx.closePath(); - gradHighlight = radFgCtx.createLinearGradient(0, 0.084112 * imageHeight, 0, 0.644859 * imageHeight); - gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); - gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); - break; + case 'type5': + radFgCtx.beginPath(); + radFgCtx.moveTo(imageWidth * 0.084112, imageHeight * 0.5); + radFgCtx.bezierCurveTo(imageWidth * 0.084112, imageHeight * 0.271028, imageWidth * 0.271028, imageHeight * 0.084112, imageWidth * 0.5, imageHeight * 0.084112); + radFgCtx.bezierCurveTo(imageWidth * 0.700934, imageHeight * 0.084112, imageWidth * 0.864485, imageHeight * 0.224299, imageWidth * 0.906542, imageHeight * 0.411214); + radFgCtx.bezierCurveTo(imageWidth * 0.911214, imageHeight * 0.439252, imageWidth * 0.911214, imageHeight * 0.518691, imageWidth * 0.845794, imageHeight * 0.537383); + radFgCtx.bezierCurveTo(imageWidth * 0.794392, imageHeight * 0.546728, imageWidth * 0.551401, imageHeight * 0.411214, imageWidth * 0.392523, imageHeight * 0.457943); + radFgCtx.bezierCurveTo(imageWidth * 0.168224, imageHeight * 0.509345, imageWidth * 0.135514, imageHeight * 0.775700, imageWidth * 0.093457, imageHeight * 0.593457); + radFgCtx.bezierCurveTo(imageWidth * 0.088785, imageHeight * 0.560747, imageWidth * 0.084112, imageHeight * 0.532710, imageWidth * 0.084112, imageHeight * 0.5); + radFgCtx.closePath(); + gradHighlight = radFgCtx.createLinearGradient(0, 0.084112 * imageHeight, 0, 0.644859 * imageHeight); + gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); + gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); + break; - case 'type1': - /* falls through */ - default: - radFgCtx.beginPath(); - radFgCtx.moveTo(imageWidth * 0.084112, imageHeight * 0.509345); - radFgCtx.bezierCurveTo(imageWidth * 0.205607, imageHeight * 0.448598, imageWidth * 0.336448, imageHeight * 0.415887, imageWidth * 0.5, imageHeight * 0.415887); - radFgCtx.bezierCurveTo(imageWidth * 0.672897, imageHeight * 0.415887, imageWidth * 0.789719, imageHeight * 0.443925, imageWidth * 0.915887, imageHeight * 0.509345); - radFgCtx.bezierCurveTo(imageWidth * 0.915887, imageHeight * 0.275700, imageWidth * 0.738317, imageHeight * 0.084112, imageWidth * 0.5, imageHeight * 0.084112); - radFgCtx.bezierCurveTo(imageWidth * 0.261682, imageHeight * 0.084112, imageWidth * 0.084112, imageHeight * 0.275700, imageWidth * 0.084112, imageHeight * 0.509345); - radFgCtx.closePath(); - gradHighlight = radFgCtx.createLinearGradient(0, 0.088785 * imageHeight, 0, 0.490654 * imageHeight); - gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); - gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); - break; + case 'type1': + /* falls through */ + default: + radFgCtx.beginPath(); + radFgCtx.moveTo(imageWidth * 0.084112, imageHeight * 0.509345); + radFgCtx.bezierCurveTo(imageWidth * 0.205607, imageHeight * 0.448598, imageWidth * 0.336448, imageHeight * 0.415887, imageWidth * 0.5, imageHeight * 0.415887); + radFgCtx.bezierCurveTo(imageWidth * 0.672897, imageHeight * 0.415887, imageWidth * 0.789719, imageHeight * 0.443925, imageWidth * 0.915887, imageHeight * 0.509345); + radFgCtx.bezierCurveTo(imageWidth * 0.915887, imageHeight * 0.275700, imageWidth * 0.738317, imageHeight * 0.084112, imageWidth * 0.5, imageHeight * 0.084112); + radFgCtx.bezierCurveTo(imageWidth * 0.261682, imageHeight * 0.084112, imageWidth * 0.084112, imageHeight * 0.275700, imageWidth * 0.084112, imageHeight * 0.509345); + radFgCtx.closePath(); + gradHighlight = radFgCtx.createLinearGradient(0, 0.088785 * imageHeight, 0, 0.490654 * imageHeight); + gradHighlight.addColorStop(0, 'rgba(255, 255, 255, 0.275)'); + gradHighlight.addColorStop(1, 'rgba(255, 255, 255, 0.015)'); + break; } radFgCtx.fillStyle = gradHighlight; radFgCtx.fill(); @@ -5111,158 +5145,158 @@ var steelseries = (function () { knobCtx = knobBuffer.getContext('2d'); switch (knob.type) { - case 'metalKnob': - // METALKNOB_FRAME - knobCtx.beginPath(); - knobCtx.moveTo(0, size * 0.5); - knobCtx.bezierCurveTo(0, size * 0.222222, size * 0.222222, 0, size * 0.5, 0); - knobCtx.bezierCurveTo(size * 0.777777, 0, size, size * 0.222222, size, size * 0.5); - knobCtx.bezierCurveTo(size, size * 0.777777, size * 0.777777, size, size * 0.5, size); - knobCtx.bezierCurveTo(size * 0.222222, size, 0, size * 0.777777, 0, size * 0.5); - knobCtx.closePath(); - grad = knobCtx.createLinearGradient(0, 0, 0, size); - grad.addColorStop(0, 'rgb(92, 95, 101)'); - grad.addColorStop(0.47, 'rgb(46, 49, 53)'); - grad.addColorStop(1, 'rgb(22, 23, 26)'); - knobCtx.fillStyle = grad; - knobCtx.fill(); + case 'metalKnob': + // METALKNOB_FRAME + knobCtx.beginPath(); + knobCtx.moveTo(0, size * 0.5); + knobCtx.bezierCurveTo(0, size * 0.222222, size * 0.222222, 0, size * 0.5, 0); + knobCtx.bezierCurveTo(size * 0.777777, 0, size, size * 0.222222, size, size * 0.5); + knobCtx.bezierCurveTo(size, size * 0.777777, size * 0.777777, size, size * 0.5, size); + knobCtx.bezierCurveTo(size * 0.222222, size, 0, size * 0.777777, 0, size * 0.5); + knobCtx.closePath(); + grad = knobCtx.createLinearGradient(0, 0, 0, size); + grad.addColorStop(0, 'rgb(92, 95, 101)'); + grad.addColorStop(0.47, 'rgb(46, 49, 53)'); + grad.addColorStop(1, 'rgb(22, 23, 26)'); + knobCtx.fillStyle = grad; + knobCtx.fill(); - // METALKNOB_MAIN - knobCtx.beginPath(); - knobCtx.moveTo(size * 0.055555, size * 0.5); - knobCtx.bezierCurveTo(size * 0.055555, size * 0.277777, size * 0.277777, size * 0.055555, size * 0.5, size * 0.055555); - knobCtx.bezierCurveTo(size * 0.722222, size * 0.055555, size * 0.944444, size * 0.277777, size * 0.944444, size * 0.5); - knobCtx.bezierCurveTo(size * 0.944444, size * 0.722222, size * 0.722222, size * 0.944444, size * 0.5, size * 0.944444); - knobCtx.bezierCurveTo(size * 0.277777, size * 0.944444, size * 0.055555, size * 0.722222, size * 0.055555, size * 0.5); - knobCtx.closePath(); - grad = knobCtx.createLinearGradient(0, 0.055555 * size, 0, 0.944443 * size); - switch (style.style) { - case 'black': - grad.addColorStop(0, 'rgb(43, 42, 47)'); - grad.addColorStop(1, 'rgb(26, 27, 32)'); + // METALKNOB_MAIN + knobCtx.beginPath(); + knobCtx.moveTo(size * 0.055555, size * 0.5); + knobCtx.bezierCurveTo(size * 0.055555, size * 0.277777, size * 0.277777, size * 0.055555, size * 0.5, size * 0.055555); + knobCtx.bezierCurveTo(size * 0.722222, size * 0.055555, size * 0.944444, size * 0.277777, size * 0.944444, size * 0.5); + knobCtx.bezierCurveTo(size * 0.944444, size * 0.722222, size * 0.722222, size * 0.944444, size * 0.5, size * 0.944444); + knobCtx.bezierCurveTo(size * 0.277777, size * 0.944444, size * 0.055555, size * 0.722222, size * 0.055555, size * 0.5); + knobCtx.closePath(); + grad = knobCtx.createLinearGradient(0, 0.055555 * size, 0, 0.944443 * size); + switch (style.style) { + case 'black': + grad.addColorStop(0, 'rgb(43, 42, 47)'); + grad.addColorStop(1, 'rgb(26, 27, 32)'); + break; + + case 'brass': + grad.addColorStop(0, 'rgb(150, 110, 54)'); + grad.addColorStop(1, 'rgb(124, 95, 61)'); + break; + + case 'silver': + /* falls through */ + default: + grad.addColorStop(0, 'rgb(204, 204, 204)'); + grad.addColorStop(1, 'rgb(87, 92, 98)'); + break; + } + knobCtx.fillStyle = grad; + knobCtx.fill(); + + // METALKNOB_LOWERHL + knobCtx.beginPath(); + knobCtx.moveTo(size * 0.777777, size * 0.833333); + knobCtx.bezierCurveTo(size * 0.722222, size * 0.722222, size * 0.611111, size * 0.666666, size * 0.5, size * 0.666666); + knobCtx.bezierCurveTo(size * 0.388888, size * 0.666666, size * 0.277777, size * 0.722222, size * 0.222222, size * 0.833333); + knobCtx.bezierCurveTo(size * 0.277777, size * 0.888888, size * 0.388888, size * 0.944444, size * 0.5, size * 0.944444); + knobCtx.bezierCurveTo(size * 0.611111, size * 0.944444, size * 0.722222, size * 0.888888, size * 0.777777, size * 0.833333); + knobCtx.closePath(); + grad = knobCtx.createRadialGradient((0.555555) * size, ((0.944444) * size), 0, ((0.555555) * size), ((0.944444) * size), 0.388888 * size); + grad.addColorStop(0, 'rgba(255, 255, 255, 0.6)'); + grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); + knobCtx.fillStyle = grad; + knobCtx.fill(); + + // METALKNOB_UPPERHL + knobCtx.beginPath(); + knobCtx.moveTo(size * 0.944444, size * 0.277777); + knobCtx.bezierCurveTo(size * 0.833333, size * 0.111111, size * 0.666666, 0, size * 0.5, 0); + knobCtx.bezierCurveTo(size * 0.333333, 0, size * 0.166666, size * 0.111111, size * 0.055555, size * 0.277777); + knobCtx.bezierCurveTo(size * 0.166666, size * 0.333333, size * 0.333333, size * 0.388888, size * 0.5, size * 0.388888); + knobCtx.bezierCurveTo(size * 0.666666, size * 0.388888, size * 0.833333, size * 0.333333, size * 0.944444, size * 0.277777); + knobCtx.closePath(); + grad = knobCtx.createRadialGradient(0.5 * size, 0, 0, ((0.5) * size), 0, 0.583333 * size); + grad.addColorStop(0, 'rgba(255, 255, 255, 0.749019)'); + grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); + knobCtx.fillStyle = grad; + knobCtx.fill(); + + // METALKNOB_INNERFRAME + knobCtx.beginPath(); + knobCtx.moveTo(size * 0.277777, size * 0.555555); + knobCtx.bezierCurveTo(size * 0.277777, size * 0.388888, size * 0.388888, size * 0.277777, size * 0.5, size * 0.277777); + knobCtx.bezierCurveTo(size * 0.611111, size * 0.277777, size * 0.777777, size * 0.388888, size * 0.777777, size * 0.555555); + knobCtx.bezierCurveTo(size * 0.777777, size * 0.666666, size * 0.611111, size * 0.777777, size * 0.5, size * 0.777777); + knobCtx.bezierCurveTo(size * 0.388888, size * 0.777777, size * 0.277777, size * 0.666666, size * 0.277777, size * 0.555555); + knobCtx.closePath(); + grad = knobCtx.createLinearGradient(0, 0.277777 * size, 0, 0.722221 * size); + grad.addColorStop(0, '#000000'); + grad.addColorStop(1, 'rgb(204, 204, 204)'); + knobCtx.fillStyle = grad; + knobCtx.fill(); + + // METALKNOB_INNERBACKGROUND + knobCtx.beginPath(); + knobCtx.moveTo(size * 0.333333, size * 0.555555); + knobCtx.bezierCurveTo(size * 0.333333, size * 0.444444, size * 0.388888, size * 0.333333, size * 0.5, size * 0.333333); + knobCtx.bezierCurveTo(size * 0.611111, size * 0.333333, size * 0.722222, size * 0.444444, size * 0.722222, size * 0.555555); + knobCtx.bezierCurveTo(size * 0.722222, size * 0.611111, size * 0.611111, size * 0.722222, size * 0.5, size * 0.722222); + knobCtx.bezierCurveTo(size * 0.388888, size * 0.722222, size * 0.333333, size * 0.611111, size * 0.333333, size * 0.555555); + knobCtx.closePath(); + grad = knobCtx.createLinearGradient(0, 0.333333 * size, 0, 0.666666 * size); + grad.addColorStop(0, 'rgb(10, 9, 1)'); + grad.addColorStop(1, 'rgb(42, 41, 37)'); + knobCtx.fillStyle = grad; + knobCtx.fill(); break; - case 'brass': - grad.addColorStop(0, 'rgb(150, 110, 54)'); - grad.addColorStop(1, 'rgb(124, 95, 61)'); + case 'standardKnob': + grad = knobCtx.createLinearGradient(0, 0, 0, size); + grad.addColorStop(0, 'rgb(180, 180, 180)'); + grad.addColorStop(0.46, 'rgb(63, 63, 63)'); + grad.addColorStop(1, 'rgb(40, 40, 40)'); + knobCtx.fillStyle = grad; + knobCtx.beginPath(); + knobCtx.arc(maxPostCenterX, maxPostCenterY, size / 2, 0, TWO_PI, true); + knobCtx.closePath(); + knobCtx.fill(); + grad = knobCtx.createLinearGradient(0, size - size * 0.77, 0, size - size * 0.77 + size * 0.77); + switch (style.style) { + case 'black': + grad.addColorStop(0, 'rgb(191, 191, 191)'); + grad.addColorStop(0.5, 'rgb(45, 44, 49)'); + grad.addColorStop(1, 'rgb(125, 126, 128)'); + break; + + case 'brass': + grad.addColorStop(0, 'rgb(223, 208, 174)'); + grad.addColorStop(0.5, 'rgb(123, 95, 63)'); + grad.addColorStop(1, 'rgb(207, 190, 157)'); + break; + + case 'silver': + /* falls through */ + default: + grad.addColorStop(0, 'rgb(215, 215, 215)'); + grad.addColorStop(0.5, 'rgb(116, 116, 116)'); + grad.addColorStop(1, 'rgb(215, 215, 215)'); + break; + } + knobCtx.fillStyle = grad; + knobCtx.beginPath(); + knobCtx.arc(maxPostCenterX, maxPostCenterY, size * 0.77 / 2, 0, TWO_PI, true); + knobCtx.closePath(); + knobCtx.fill(); + + grad = knobCtx.createRadialGradient(maxPostCenterX, maxPostCenterY, 0, maxPostCenterX, maxPostCenterY, size * 0.77 / 2); + grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); + grad.addColorStop(0.75, 'rgba(0, 0, 0, 0)'); + grad.addColorStop(0.76, 'rgba(0, 0, 0, 0.01)'); + grad.addColorStop(1, 'rgba(0, 0, 0, 0.2)'); + knobCtx.fillStyle = grad; + knobCtx.beginPath(); + knobCtx.arc(maxPostCenterX, maxPostCenterY, size * 0.77 / 2, 0, TWO_PI, true); + knobCtx.closePath(); + knobCtx.fill(); break; - - case 'silver': - /* falls through */ - default: - grad.addColorStop(0, 'rgb(204, 204, 204)'); - grad.addColorStop(1, 'rgb(87, 92, 98)'); - break; - } - knobCtx.fillStyle = grad; - knobCtx.fill(); - - // METALKNOB_LOWERHL - knobCtx.beginPath(); - knobCtx.moveTo(size * 0.777777, size * 0.833333); - knobCtx.bezierCurveTo(size * 0.722222, size * 0.722222, size * 0.611111, size * 0.666666, size * 0.5, size * 0.666666); - knobCtx.bezierCurveTo(size * 0.388888, size * 0.666666, size * 0.277777, size * 0.722222, size * 0.222222, size * 0.833333); - knobCtx.bezierCurveTo(size * 0.277777, size * 0.888888, size * 0.388888, size * 0.944444, size * 0.5, size * 0.944444); - knobCtx.bezierCurveTo(size * 0.611111, size * 0.944444, size * 0.722222, size * 0.888888, size * 0.777777, size * 0.833333); - knobCtx.closePath(); - grad = knobCtx.createRadialGradient((0.555555) * size, ((0.944444) * size), 0, ((0.555555) * size), ((0.944444) * size), 0.388888 * size); - grad.addColorStop(0, 'rgba(255, 255, 255, 0.6)'); - grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); - knobCtx.fillStyle = grad; - knobCtx.fill(); - - // METALKNOB_UPPERHL - knobCtx.beginPath(); - knobCtx.moveTo(size * 0.944444, size * 0.277777); - knobCtx.bezierCurveTo(size * 0.833333, size * 0.111111, size * 0.666666, 0, size * 0.5, 0); - knobCtx.bezierCurveTo(size * 0.333333, 0, size * 0.166666, size * 0.111111, size * 0.055555, size * 0.277777); - knobCtx.bezierCurveTo(size * 0.166666, size * 0.333333, size * 0.333333, size * 0.388888, size * 0.5, size * 0.388888); - knobCtx.bezierCurveTo(size * 0.666666, size * 0.388888, size * 0.833333, size * 0.333333, size * 0.944444, size * 0.277777); - knobCtx.closePath(); - grad = knobCtx.createRadialGradient(0.5 * size, 0, 0, ((0.5) * size), 0, 0.583333 * size); - grad.addColorStop(0, 'rgba(255, 255, 255, 0.749019)'); - grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); - knobCtx.fillStyle = grad; - knobCtx.fill(); - - // METALKNOB_INNERFRAME - knobCtx.beginPath(); - knobCtx.moveTo(size * 0.277777, size * 0.555555); - knobCtx.bezierCurveTo(size * 0.277777, size * 0.388888, size * 0.388888, size * 0.277777, size * 0.5, size * 0.277777); - knobCtx.bezierCurveTo(size * 0.611111, size * 0.277777, size * 0.777777, size * 0.388888, size * 0.777777, size * 0.555555); - knobCtx.bezierCurveTo(size * 0.777777, size * 0.666666, size * 0.611111, size * 0.777777, size * 0.5, size * 0.777777); - knobCtx.bezierCurveTo(size * 0.388888, size * 0.777777, size * 0.277777, size * 0.666666, size * 0.277777, size * 0.555555); - knobCtx.closePath(); - grad = knobCtx.createLinearGradient(0, 0.277777 * size, 0, 0.722221 * size); - grad.addColorStop(0, '#000000'); - grad.addColorStop(1, 'rgb(204, 204, 204)'); - knobCtx.fillStyle = grad; - knobCtx.fill(); - - // METALKNOB_INNERBACKGROUND - knobCtx.beginPath(); - knobCtx.moveTo(size * 0.333333, size * 0.555555); - knobCtx.bezierCurveTo(size * 0.333333, size * 0.444444, size * 0.388888, size * 0.333333, size * 0.5, size * 0.333333); - knobCtx.bezierCurveTo(size * 0.611111, size * 0.333333, size * 0.722222, size * 0.444444, size * 0.722222, size * 0.555555); - knobCtx.bezierCurveTo(size * 0.722222, size * 0.611111, size * 0.611111, size * 0.722222, size * 0.5, size * 0.722222); - knobCtx.bezierCurveTo(size * 0.388888, size * 0.722222, size * 0.333333, size * 0.611111, size * 0.333333, size * 0.555555); - knobCtx.closePath(); - grad = knobCtx.createLinearGradient(0, 0.333333 * size, 0, 0.666666 * size); - grad.addColorStop(0, 'rgb(10, 9, 1)'); - grad.addColorStop(1, 'rgb(42, 41, 37)'); - knobCtx.fillStyle = grad; - knobCtx.fill(); - break; - - case 'standardKnob': - grad = knobCtx.createLinearGradient(0, 0, 0, size); - grad.addColorStop(0, 'rgb(180, 180, 180)'); - grad.addColorStop(0.46, 'rgb(63, 63, 63)'); - grad.addColorStop(1, 'rgb(40, 40, 40)'); - knobCtx.fillStyle = grad; - knobCtx.beginPath(); - knobCtx.arc(maxPostCenterX, maxPostCenterY, size / 2, 0, TWO_PI, true); - knobCtx.closePath(); - knobCtx.fill(); - grad = knobCtx.createLinearGradient(0, size - size * 0.77, 0, size - size * 0.77 + size * 0.77); - switch (style.style) { - case 'black': - grad.addColorStop(0, 'rgb(191, 191, 191)'); - grad.addColorStop(0.5, 'rgb(45, 44, 49)'); - grad.addColorStop(1, 'rgb(125, 126, 128)'); - break; - - case 'brass': - grad.addColorStop(0, 'rgb(223, 208, 174)'); - grad.addColorStop(0.5, 'rgb(123, 95, 63)'); - grad.addColorStop(1, 'rgb(207, 190, 157)'); - break; - - case 'silver': - /* falls through */ - default: - grad.addColorStop(0, 'rgb(215, 215, 215)'); - grad.addColorStop(0.5, 'rgb(116, 116, 116)'); - grad.addColorStop(1, 'rgb(215, 215, 215)'); - break; - } - knobCtx.fillStyle = grad; - knobCtx.beginPath(); - knobCtx.arc(maxPostCenterX, maxPostCenterY, size * 0.77 / 2, 0, TWO_PI, true); - knobCtx.closePath(); - knobCtx.fill(); - - grad = knobCtx.createRadialGradient(maxPostCenterX, maxPostCenterY, 0, maxPostCenterX, maxPostCenterY, size * 0.77 / 2); - grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); - grad.addColorStop(0.75, 'rgba(0, 0, 0, 0)'); - grad.addColorStop(0.76, 'rgba(0, 0, 0, 0.01)'); - grad.addColorStop(1, 'rgba(0, 0, 0, 0.2)'); - knobCtx.fillStyle = grad; - knobCtx.beginPath(); - knobCtx.arc(maxPostCenterX, maxPostCenterY, size * 0.77 / 2, 0, TWO_PI, true); - knobCtx.closePath(); - knobCtx.fill(); - break; } // cache the buffer @@ -5286,94 +5320,94 @@ var steelseries = (function () { ledCtx = ledBuffer.getContext('2d'); switch (state) { - case 0: // LED OFF - // OFF Gradient - grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); - grad.addColorStop(0, ledColor.innerColor1_OFF); - grad.addColorStop(0.2, ledColor.innerColor2_OFF); - grad.addColorStop(1, ledColor.outerColor_OFF); - ledCtx.fillStyle = grad; + case 0: // LED OFF + // OFF Gradient + grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); + grad.addColorStop(0, ledColor.innerColor1_OFF); + grad.addColorStop(0.2, ledColor.innerColor2_OFF); + grad.addColorStop(1, ledColor.outerColor_OFF); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); - // InnerShadow - grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); - grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); - grad.addColorStop(0.8, 'rgba(0, 0, 0, 0)'); - grad.addColorStop(1, 'rgba(0, 0, 0, 0.4)'); - ledCtx.fillStyle = grad; + // InnerShadow + grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); + grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); + grad.addColorStop(0.8, 'rgba(0, 0, 0, 0)'); + grad.addColorStop(1, 'rgba(0, 0, 0, 0.4)'); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); - // LightReflex - grad = ledCtx.createLinearGradient(0, 0.35 * size, 0, 0.35 * size + 0.15 * size); - grad.addColorStop(0, 'rgba(255, 255, 255, 0.4)'); - grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); - ledCtx.fillStyle = grad; + // LightReflex + grad = ledCtx.createLinearGradient(0, 0.35 * size, 0, 0.35 * size + 0.15 * size); + grad.addColorStop(0, 'rgba(255, 255, 255, 0.4)'); + grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, 0.35 * size + 0.2 * size / 2, size * 0.2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); - break; + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, 0.35 * size + 0.2 * size / 2, size * 0.2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); + break; - case 1: // LED ON - // ON Gradient - grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); - grad.addColorStop(0, ledColor.innerColor1_ON); - grad.addColorStop(0.2, ledColor.innerColor2_ON); - grad.addColorStop(1, ledColor.outerColor_ON); - ledCtx.fillStyle = grad; + case 1: // LED ON + // ON Gradient + grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); + grad.addColorStop(0, ledColor.innerColor1_ON); + grad.addColorStop(0.2, ledColor.innerColor2_ON); + grad.addColorStop(1, ledColor.outerColor_ON); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); - // InnerShadow - grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); - grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); - grad.addColorStop(0.8, 'rgba(0, 0, 0, 0)'); - grad.addColorStop(1, 'rgba(0, 0, 0, 0.4)'); - ledCtx.fillStyle = grad; + // InnerShadow + grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size * 0.5 / 2); + grad.addColorStop(0, 'rgba(0, 0, 0, 0)'); + grad.addColorStop(0.8, 'rgba(0, 0, 0, 0)'); + grad.addColorStop(1, 'rgba(0, 0, 0, 0.4)'); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, ledCenterY, size * 0.5 / 2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); - // LightReflex - grad = ledCtx.createLinearGradient(0, 0.35 * size, 0, 0.35 * size + 0.15 * size); - grad.addColorStop(0, 'rgba(255, 255, 255, 0.4)'); - grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); - ledCtx.fillStyle = grad; + // LightReflex + grad = ledCtx.createLinearGradient(0, 0.35 * size, 0, 0.35 * size + 0.15 * size); + grad.addColorStop(0, 'rgba(255, 255, 255, 0.4)'); + grad.addColorStop(1, 'rgba(255, 255, 255, 0)'); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, 0.35 * size + 0.2 * size / 2, size * 0.2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, 0.35 * size + 0.2 * size / 2, size * 0.2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); - // Corona - grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size / 2); - grad.addColorStop(0, setAlpha(ledColor.coronaColor, 0)); - grad.addColorStop(0.6, setAlpha(ledColor.coronaColor, 0.4)); - grad.addColorStop(0.7, setAlpha(ledColor.coronaColor, 0.25)); - grad.addColorStop(0.8, setAlpha(ledColor.coronaColor, 0.15)); - grad.addColorStop(0.85, setAlpha(ledColor.coronaColor, 0.05)); - grad.addColorStop(1, setAlpha(ledColor.coronaColor, 0)); - ledCtx.fillStyle = grad; + // Corona + grad = ledCtx.createRadialGradient(ledCenterX, ledCenterY, 0, ledCenterX, ledCenterY, size / 2); + grad.addColorStop(0, setAlpha(ledColor.coronaColor, 0)); + grad.addColorStop(0.6, setAlpha(ledColor.coronaColor, 0.4)); + grad.addColorStop(0.7, setAlpha(ledColor.coronaColor, 0.25)); + grad.addColorStop(0.8, setAlpha(ledColor.coronaColor, 0.15)); + grad.addColorStop(0.85, setAlpha(ledColor.coronaColor, 0.05)); + grad.addColorStop(1, setAlpha(ledColor.coronaColor, 0)); + ledCtx.fillStyle = grad; - ledCtx.beginPath(); - ledCtx.arc(ledCenterX, ledCenterY, size / 2, 0, TWO_PI, true); - ledCtx.closePath(); - ledCtx.fill(); - break; + ledCtx.beginPath(); + ledCtx.arc(ledCenterX, ledCenterY, size / 2, 0, TWO_PI, true); + ledCtx.closePath(); + ledCtx.fill(); + break; } // cache the buffer createLedImage.cache[cacheKey] = ledBuffer; @@ -5680,23 +5714,23 @@ var steelseries = (function () { trendCtx.translate(width * 0.5, width * 0.5); // Must draw the active section last so the 'glow' is on top switch (onSection.state) { - case 'up': - drawDownArrow(); - drawEquals(); - drawUpArrow(); - break; - case 'steady': - drawDownArrow(); - drawUpArrow(); - drawEquals(); - break; - case 'down': - /* falls through */ - default: - drawUpArrow(); - drawEquals(); - drawDownArrow(); - break; + case 'up': + drawDownArrow(); + drawEquals(); + drawUpArrow(); + break; + case 'steady': + drawDownArrow(); + drawUpArrow(); + drawEquals(); + break; + case 'down': + /* falls through */ + default: + drawUpArrow(); + drawEquals(); + drawDownArrow(); + break; } // cache the buffer createTrendIndicator.cache[cacheKey] = trendBuffer; @@ -5757,127 +5791,127 @@ var steelseries = (function () { //***************************************** T E X T U R E S **************************************************** var carbonBuffer = drawToBuffer(12, 12, function (ctx) { - var imageWidth = ctx.canvas.width, - imageHeight = ctx.canvas.height, - offsetX = 0, - offsetY = 0, - grad; + var imageWidth = ctx.canvas.width, + imageHeight = ctx.canvas.height, + offsetX = 0, + offsetY = 0, + grad; - ctx.save(); + ctx.save(); - // RULB - ctx.save(); - ctx.beginPath(); - ctx.rect(0, 0, imageWidth * 0.5, imageHeight * 0.5); - ctx.closePath(); - ctx.restore(); + // RULB + ctx.save(); + ctx.beginPath(); + ctx.rect(0, 0, imageWidth * 0.5, imageHeight * 0.5); + ctx.closePath(); + ctx.restore(); - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, 'rgb(35, 35, 35)'); - grad.addColorStop(1, 'rgb(23, 23, 23)'); - ctx.fillStyle = grad; - ctx.fill(); + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, 'rgb(35, 35, 35)'); + grad.addColorStop(1, 'rgb(23, 23, 23)'); + ctx.fillStyle = grad; + ctx.fill(); - // RULF - ctx.save(); - ctx.beginPath(); - ctx.rect(imageWidth * 0.083333, 0, imageWidth * 0.333333, imageHeight * 0.416666); - ctx.closePath(); - ctx.restore(); - offsetX = 0.083333; - offsetY = 0; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, 'rgb(38, 38, 38)'); - grad.addColorStop(1, 'rgb(30, 30, 30)'); - ctx.fillStyle = grad; - ctx.fill(); + // RULF + ctx.save(); + ctx.beginPath(); + ctx.rect(imageWidth * 0.083333, 0, imageWidth * 0.333333, imageHeight * 0.416666); + ctx.closePath(); + ctx.restore(); + offsetX = 0.083333; + offsetY = 0; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, 'rgb(38, 38, 38)'); + grad.addColorStop(1, 'rgb(30, 30, 30)'); + ctx.fillStyle = grad; + ctx.fill(); - // RLRB - ctx.save(); - ctx.beginPath(); - ctx.rect(imageWidth * 0.5, imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5); - ctx.closePath(); - ctx.restore(); - offsetX = 0.5; - offsetY = 0.5; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, 'rgb(35, 35, 35)'); - grad.addColorStop(1, 'rgb(23, 23, 23)'); - ctx.fillStyle = grad; - ctx.fill(); + // RLRB + ctx.save(); + ctx.beginPath(); + ctx.rect(imageWidth * 0.5, imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5); + ctx.closePath(); + ctx.restore(); + offsetX = 0.5; + offsetY = 0.5; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, 'rgb(35, 35, 35)'); + grad.addColorStop(1, 'rgb(23, 23, 23)'); + ctx.fillStyle = grad; + ctx.fill(); - // RLRF - ctx.save(); - ctx.beginPath(); - ctx.rect(imageWidth * 0.583333, imageHeight * 0.5, imageWidth * 0.333333, imageHeight * 0.416666); - ctx.closePath(); - ctx.restore(); - offsetX = 0.583333; - offsetY = 0.5; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, 'rgb(38, 38, 38)'); - grad.addColorStop(1, 'rgb(30, 30, 30)'); - ctx.fillStyle = grad; - ctx.fill(); + // RLRF + ctx.save(); + ctx.beginPath(); + ctx.rect(imageWidth * 0.583333, imageHeight * 0.5, imageWidth * 0.333333, imageHeight * 0.416666); + ctx.closePath(); + ctx.restore(); + offsetX = 0.583333; + offsetY = 0.5; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, 'rgb(38, 38, 38)'); + grad.addColorStop(1, 'rgb(30, 30, 30)'); + ctx.fillStyle = grad; + ctx.fill(); - // RURB - ctx.save(); - ctx.beginPath(); - ctx.rect(imageWidth * 0.5, 0, imageWidth * 0.5, imageHeight * 0.5); - ctx.closePath(); - ctx.restore(); - offsetX = 0.5; - offsetY = 0; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, '#303030'); - grad.addColorStop(1, 'rgb(40, 40, 40)'); - ctx.fillStyle = grad; - ctx.fill(); + // RURB + ctx.save(); + ctx.beginPath(); + ctx.rect(imageWidth * 0.5, 0, imageWidth * 0.5, imageHeight * 0.5); + ctx.closePath(); + ctx.restore(); + offsetX = 0.5; + offsetY = 0; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, '#303030'); + grad.addColorStop(1, 'rgb(40, 40, 40)'); + ctx.fillStyle = grad; + ctx.fill(); - // RURF - ctx.save(); - ctx.beginPath(); - ctx.rect(imageWidth * 0.583333, imageHeight * 0.083333, imageWidth * 0.333333, imageHeight * 0.416666); - ctx.closePath(); - ctx.restore(); - offsetX = 0.583333; - offsetY = 0.083333; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, 'rgb(53, 53, 53)'); - grad.addColorStop(1, 'rgb(45, 45, 45)'); - ctx.fillStyle = grad; - ctx.fill(); + // RURF + ctx.save(); + ctx.beginPath(); + ctx.rect(imageWidth * 0.583333, imageHeight * 0.083333, imageWidth * 0.333333, imageHeight * 0.416666); + ctx.closePath(); + ctx.restore(); + offsetX = 0.583333; + offsetY = 0.083333; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, 'rgb(53, 53, 53)'); + grad.addColorStop(1, 'rgb(45, 45, 45)'); + ctx.fillStyle = grad; + ctx.fill(); - // RLLB - ctx.save(); - ctx.beginPath(); - ctx.rect(0, imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5); - ctx.closePath(); - ctx.restore(); - offsetX = 0; - offsetY = 0.5; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, '#303030'); - grad.addColorStop(1, '#282828'); - ctx.fillStyle = grad; - ctx.fill(); + // RLLB + ctx.save(); + ctx.beginPath(); + ctx.rect(0, imageHeight * 0.5, imageWidth * 0.5, imageHeight * 0.5); + ctx.closePath(); + ctx.restore(); + offsetX = 0; + offsetY = 0.5; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.5 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, '#303030'); + grad.addColorStop(1, '#282828'); + ctx.fillStyle = grad; + ctx.fill(); - // RLLF - ctx.save(); - ctx.beginPath(); - ctx.rect(imageWidth * 0.083333, imageHeight * 0.583333, imageWidth * 0.333333, imageHeight * 0.416666); - ctx.closePath(); - ctx.restore(); - offsetX = 0.083333; - offsetY = 0.583333; - grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); - grad.addColorStop(0, '#353535'); - grad.addColorStop(1, '#2d2d2d'); - ctx.fillStyle = grad; - ctx.fill(); + // RLLF + ctx.save(); + ctx.beginPath(); + ctx.rect(imageWidth * 0.083333, imageHeight * 0.583333, imageWidth * 0.333333, imageHeight * 0.416666); + ctx.closePath(); + ctx.restore(); + offsetX = 0.083333; + offsetY = 0.583333; + grad = ctx.createLinearGradient(0, offsetY * imageHeight, 0, 0.416666 * imageHeight + offsetY * imageHeight); + grad.addColorStop(0, '#353535'); + grad.addColorStop(1, '#2d2d2d'); + ctx.fillStyle = grad; + ctx.fill(); - ctx.restore(); - }); + ctx.restore(); + }); var punchedSheetBuffer = drawToBuffer(15, 15, function (ctx) { var imageWidth = ctx.canvas.width, @@ -5999,7 +6033,7 @@ var steelseries = (function () { if (radius !== 0) { totR = totG = totB = 0; } - for (x = 0; x < width; x ++) { + for (x = 0; x < width; x++) { indx = (y * width * 4) + (x * 4); tr = red; tg = green; @@ -6013,12 +6047,12 @@ var steelseries = (function () { if (monochrome) { n = ((2 * Math.random() - 1) * variation) | 0; - inPixels.data[indx] = clamp(tr + n); + inPixels.data[indx] = clamp(tr + n); inPixels.data[indx + 1] = clamp(tg + n); inPixels.data[indx + 2] = clamp(tb + n); inPixels.data[indx + 3] = alpha; } else { - inPixels.data[indx] = random(tr, variation); + inPixels.data[indx] = random(tr, variation); inPixels.data[indx + 1] = random(tg, variation); inPixels.data[indx + 2] = random(tb, variation); inPixels.data[indx + 3] = alpha; @@ -6056,7 +6090,7 @@ var steelseries = (function () { indx = 0; for (y = 0; y < height; y++) { totR = totG = totB = 0; - for (x = 0; x < radius ; x++) { + for (x = 0; x < radius; x++) { i = (indx + x) * 4; totR += inPix.data[i]; totG += inPix.data[i + 1]; @@ -6174,35 +6208,35 @@ var steelseries = (function () { indx, pixColor, buffer, bufferCtx; -// Original Version using rotated lines -/* - ctx.save(); - ctx.lineWidth = 1.5; - ctx.translate(centerX, centerY); - ctx.rotate(rotationOffset); - ctx.translate(-centerX, -centerY); - for (i = 0, size = fractions.length - 1; i < size; i++) { - startAngle = TWO_PI * fractions[i]; - stopAngle = TWO_PI * fractions[i + 1]; - range = stopAngle - startAngle; - startColor = colors[i]; - stopColor = colors[i + 1]; - for (angle = startAngle; angle < stopAngle; angle += angleStep) { - ctx.beginPath(); - ctx.fillStyle = getColorFromFraction(startColor, stopColor, range, (angle - startAngle)).getRgbaColor(); - ctx.strokeStyle = ctx.fillStyle; - if (innerX > 0) { - ctx.arc(centerX, centerY, innerX, angle + angleStep, angle, true); - } else { - ctx.moveTo(centerX, centerY); - } - ctx.arc(centerX, centerY, outerX, angle, angle + angleStep); - ctx.fill(); - ctx.stroke(); - } - } -*/ -// End - Original Version + // Original Version using rotated lines + /* + ctx.save(); + ctx.lineWidth = 1.5; + ctx.translate(centerX, centerY); + ctx.rotate(rotationOffset); + ctx.translate(-centerX, -centerY); + for (i = 0, size = fractions.length - 1; i < size; i++) { + startAngle = TWO_PI * fractions[i]; + stopAngle = TWO_PI * fractions[i + 1]; + range = stopAngle - startAngle; + startColor = colors[i]; + stopColor = colors[i + 1]; + for (angle = startAngle; angle < stopAngle; angle += angleStep) { + ctx.beginPath(); + ctx.fillStyle = getColorFromFraction(startColor, stopColor, range, (angle - startAngle)).getRgbaColor(); + ctx.strokeStyle = ctx.fillStyle; + if (innerX > 0) { + ctx.arc(centerX, centerY, innerX, angle + angleStep, angle, true); + } else { + ctx.moveTo(centerX, centerY); + } + ctx.arc(centerX, centerY, outerX, angle, angle + angleStep); + ctx.fill(); + ctx.stroke(); + } + } + */ + // End - Original Version // Create pixel array pixels = ctx.createImageData(diameter, diameter); @@ -6223,7 +6257,7 @@ var steelseries = (function () { } // The pixel array is addressed as 4 elements per pixel [r,g,b,a] indx = ((diameter - y) * diameter * 4) + (x * 4); // plot is 180 rotated from orginal method, so apply a simple invert (diameter - y) - pixels.data[indx] = pixColor[0]; + pixels.data[indx] = pixColor[0]; pixels.data[indx + 1] = pixColor[1]; pixels.data[indx + 2] = pixColor[2]; pixels.data[indx + 3] = alpha; @@ -6279,7 +6313,7 @@ var steelseries = (function () { } // The pixel array is addressed as 4 elements per pixel [r,g,b,a] indx = ((height - y) * width * 4) + (x * 4); // plot is 180 rotated from orginal method, so apply a simple invert (height - y) - pixels.data[indx] = pixColor[0]; + pixels.data[indx] = pixColor[0]; pixels.data[indx + 1] = pixColor[0]; pixels.data[indx + 2] = pixColor[0]; pixels.data[indx + 3] = alpha; @@ -6370,9 +6404,11 @@ var steelseries = (function () { } function section(start, stop, color) { - return {start : start, - stop : stop, - color : color}; + return { + start: start, + stop: stop, + color: color + }; } Math.log10 = function (value) { @@ -6422,7 +6458,7 @@ var steelseries = (function () { ctx.lineTo(x, y + radius); ctx.quadraticCurveTo(x, y, x + radius, y); ctx.closePath(); -// ctx.stroke(); + // ctx.stroke(); } function createBuffer(width, height) { @@ -6498,15 +6534,15 @@ var steelseries = (function () { delta = max - min; saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min); switch (max) { - case red: - hue = (green - blue) / delta + (green < blue ? 6 : 0); - break; - case green: - hue = (blue - red) / delta + 2; - break; - case blue: - hue = (red - green) / delta + 4; - break; + case red: + hue = (green - blue) / delta + (green < blue ? 6 : 0); + break; + case green: + hue = (blue - red) / delta + 2; + break; + case blue: + hue = (red - green) / delta + 4; + break; } hue /= 6; } @@ -6522,36 +6558,36 @@ var steelseries = (function () { t = brightness * (1 - (1 - f) * saturation); switch (i % 6) { - case 0: - r = brightness; - g = t; - b = p; - break; - case 1: - r = q; - g = brightness; - b = p; - break; - case 2: - r = p; - g = brightness; - b = t; - break; - case 3: - r = p; - g = q; - b = brightness; - break; - case 4: - r = t; - g = p; - b = brightness; - break; - case 5: - r = brightness; - g = p; - b = q; - break; + case 0: + r = brightness; + g = t; + b = p; + break; + case 1: + r = q; + g = brightness; + b = p; + break; + case 2: + r = p; + g = brightness; + b = t; + break; + case 3: + r = p; + g = q; + b = brightness; + break; + case 4: + r = t; + g = p; + b = brightness; + break; + case 5: + r = brightness; + g = p; + b = q; + break; } return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]; @@ -6573,15 +6609,15 @@ var steelseries = (function () { hue = 0; // achromatic } else { switch (max) { - case r: - hue = (g - b) / delta + (g < b ? 6 : 0); - break; - case g: - hue = (b - r) / delta + 2; - break; - case b: - hue = (r - g) / delta + 4; - break; + case r: + hue = (g - b) / delta + (g < b ? 6 : 0); + break; + case g: + hue = (b - r) / delta + 2; + break; + case b: + hue = (r - g) / delta + 4; + break; } hue /= 6; } @@ -6634,11 +6670,11 @@ var steelseries = (function () { // shim layer var requestAnimFrame = (function () { - return window.requestAnimationFrame || + return window.requestAnimationFrame || window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 16); }; @@ -6933,42 +6969,42 @@ var steelseries = (function () { //********************************** E X P O R T F U N C T I O N S ******************************************* return { // Components EXTERNAL : INTERNAL - Radial : radial, - RadialBargraph : radialBargraph, + Radial: radial, + RadialBargraph: radialBargraph, DisplaySingle: displaySingle, - WindDirection : windDirection, - Led : led, + WindDirection: windDirection, + Led: led, Odometer: odometer, - // Images - drawFrame : drawRadialFrameImage, - drawBackground : drawRadialBackgroundImage, - drawForeground : drawRadialForegroundImage, + // /images + drawFrame: drawRadialFrameImage, + drawBackground: drawRadialBackgroundImage, + drawForeground: drawRadialForegroundImage, // Tools - rgbaColor : RgbaColor, - ConicalGradient : ConicalGradient, - setAlpha : setAlpha, - getColorFromFraction : getColorFromFraction, - gradientWrapper : GradientWrapper, + rgbaColor: RgbaColor, + ConicalGradient: ConicalGradient, + setAlpha: setAlpha, + getColorFromFraction: getColorFromFraction, + gradientWrapper: GradientWrapper, // Constants - BackgroundColor : backgroundColor, - LcdColor : lcdColor, - ColorDef : color, - LedColor : ledColor, - GaugeType : gaugeType, + BackgroundColor: backgroundColor, + LcdColor: lcdColor, + ColorDef: color, + LedColor: ledColor, + GaugeType: gaugeType, Orientation: orientation, - FrameDesign : frameDesign, - PointerType : pointerType, - ForegroundType : foregroundType, - KnobType : knobType, + FrameDesign: frameDesign, + PointerType: pointerType, + ForegroundType: foregroundType, + KnobType: knobType, KnobStyle: knobStyle, LabelNumberFormat: labelNumberFormat, TickLabelOrientation: tickLabelOrientation, TrendState: trendState, // Other - Section : section + Section: section }; }()); diff --git a/oldindex.htm b/oldindex.htm deleted file mode 100644 index c031d80..0000000 --- a/oldindex.htm +++ /dev/null @@ -1,242 +0,0 @@ - -
- -
- -
-

Weather

-
-
-
- -
- -
- -
- -
-

Almanac

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dawn:Sun Rise:Moon Rise:MoonVisible % -
Dusk:Sun Set:Moon Set:
Daylight:Day Length:Moon Phase:
Current conditions:
-
-
-
-
-
- -
- -
-

Conditions at local time

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Temperature and Humidity
Temperature  - Dew Point  -
Windchill  - Humidity %
Heat Index Apparent TemperatureFeels Like 
Temp change last hour 
Rainfall
Rainfall Today  - Rainfall Rate /hr -
Rainfall This Month  - Rainfall This Year  -
Rainfall Last Hour  - Last rainfall
Rainfall Since Midnight Rainfall Last 24 Hours  -
Wind
Wind Speed (gust)  - Wind Speed (avg)  -
Wind Bearing° - Beaufort
Wind Variation (last 10 minutes)From ° to °
Pressure (sea - level)
Barometer  -  /hr
Solar
Solar Radiation W/m²Evapotranspiration Today  -
UV Index
-
-

Page updated .

-
-
-
-
-
- -
-
-
-

Welcome to

-

The weather station in use is the
- This page is updated every minutes. The - meteorological day used at this station ends at . -

-

Forecast:

-
-
-
-
-
-
- diff --git a/today.htm b/today.htm deleted file mode 100644 index 30eb1b6..0000000 --- a/today.htm +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - Cumulus MX - - - - - - - - - - - - - - - - - - - -
-
-
-

Today

-
-
-
-
-
-
-
-

Today's data

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Temperature and Humidity
High Temperature at
Low Temperature at
Temperature Range 
High Apparent Temperature at
Low Apparent Temperature at
High Feels Like at
Low Feels Like at
Low Wind Chill at
High Heat Index at
High Humidity %at
Low Humidity %at
Rainfall
Rainfall Today 
Rainfall Rate Max /hrat
High Hourly Rainfall at
High 24 Hour Rainfall at
Days Since Last Dry Day
Days Since It Last Rained
Wind
High Gust at
High Speed (10 minute average)  ()at
Wind Run 
Dominant Direction°
Pressure (sea level)
High Pressure at
Low Pressure at
Solar
High Solar Radiation W/m2at
Hours of Sunshine hrs
High UV Indexat
-

Page data updated .

-
-
-
-
-
-
-
-
-
-

Welcome to

-

This page shows the highs, lows and current values for today.
- This page is updated every minutes. The meteorological day used at this station ends at - . -

-
-
-
-
-
-
- - - - \ No newline at end of file diff --git a/today/index.php b/today/index.php new file mode 100644 index 0000000..1edd33a --- /dev/null +++ b/today/index.php @@ -0,0 +1,148 @@ + + + + + + + + + +
+ +
+

Data for today ()

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Temperature and Humidity
High Temperature at
Low Temperature at
Temperature Range 
High Feels Like at
Low Feels Like at
Low Wind Chill at
High Heat Index at
High Humidity %at
Low Humidity %at
Rainfall
Rainfall Today 
Rainfall Rate Max /hrat
High Hourly Rainfall at
High 24 Hour Rainfall at
Days Since Last Dry Day
Days Since It Last Rained
Wind
High Gust at
High Speed (10 minute average)  ()at
Wind Run 
Dominant Direction°
Pressure (sea level)
High Pressure at
Low Pressure at
+ Page data updated +
+ +
+ + + \ No newline at end of file diff --git a/yesterday.htm b/yesterday.htm deleted file mode 100644 index f04923a..0000000 --- a/yesterday.htm +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - Cumulus MX - - - - - - - - - - - - - - - - - - - -
-
-
-

Yesterday

-
-
-
-
-
-
-
-

Yesterday's data

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Temperature and Humidity
High Temperature at
Low Temperature at
Temperature Range 
High Apparent Temperature at
Low Apparent Temperature at
High Feels Like at
Low Feels Like at
Low Wind Chill at
High Heat Index at
High Humidity %at
Low Humidity %at
Rainfall
Rainfall Yesterday 
Rainfall Rate Max /hrat
High Hourly Rainfall at
High 24 Hour Rainfall at
Wind
High Gust at
High Speed (10 minute average)  ()at
Wind Run 
Dominant Direction°
Pressure (sea level)
High Pressure at
Low Pressure at
Solar
High Solar Radiation W/m²at
Hours of Sunshine hrs
High UV Indexat
-

Page updated .

-
-
-
-
-
-
-
-
-
-

Welcome to

-

This page shows a summary of the data for the 24 hrs up to local time.

-
-
-
-
-
-
- - - \ No newline at end of file diff --git a/yesterday/index.php b/yesterday/index.php new file mode 100644 index 0000000..b93257a --- /dev/null +++ b/yesterday/index.php @@ -0,0 +1,149 @@ + + + + + + + + + +
+ +
+

Data for today ()

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Temperature and Humidity
High Temperature at
Low Temperature at
Temperature Range 
High Feels Like at
Low Feels Like at
Low Wind Chill at
High Heat Index at
High Humidity %at
Low Humidity %at
Rainfall
Rainfall Today 
Rainfall Rate Max /hrat
High Hourly Rainfall at
High 24 Hour Rainfall at
Days Since Last Dry Day
Days Since It Last Rained
Wind
High Gust at
High Speed (10 minute average)  ()at
Wind Run 
Dominant Direction° +
Pressure (sea level)
High Pressure at
Low Pressure at
+ Page data updated +
+ +
+ + + \ No newline at end of file From d719a3af9a2cdd4ecd5ad655d4f21f5244ee3ff9 Mon Sep 17 00:00:00 2001 From: floppydiskette Date: Wed, 11 Dec 2024 23:10:01 +0000 Subject: [PATCH 2/2] Add editorconfig, remove unused assets --- .editorconfig | 8 ++ css/colours.css | 40 ------ css/gauges.css | 131 ++++++++++---------- css/mx-templates.css | 249 -------------------------------------- css/w3Pro.css | 247 ------------------------------------- css/wah.css | 176 +++++++++++++-------------- images/CumulusMX-Logo.png | Bin 22972 -> 0 bytes images/favicon.png | Bin 58136 -> 0 bytes images/picture.jpg | Bin 12929 -> 0 bytes includes/header.inc.php | 2 +- 10 files changed, 166 insertions(+), 687 deletions(-) create mode 100644 .editorconfig delete mode 100644 css/colours.css delete mode 100644 css/mx-templates.css delete mode 100644 css/w3Pro.css delete mode 100644 images/CumulusMX-Logo.png delete mode 100644 images/favicon.png delete mode 100644 images/picture.jpg diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d3fcdc6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +charset = utf-8 diff --git a/css/colours.css b/css/colours.css deleted file mode 100644 index 2bfeddc..0000000 --- a/css/colours.css +++ /dev/null @@ -1,40 +0,0 @@ -/* ------------------------------------------------------------------- - * Colours for the CumulusMX Alternative Interface - * Produced using w3Schools colour generator - * - * Key Colour: #4e5b31 - * - * Theme modified to change font 'color's to either lightest or darkest - * theme colour. Also modified names for text, borders & hover colours. - * I have added a few extras. Not all are used. - * Neil Thomas - ------------------------------------------------------------------*/ - -/* Check that your theme is named as shown below */ - -.w3-theme-white {color:#2e5473; background-color:#FFFFFF;} -.w3-theme-l5 {color:#2e5473; background-color:#f7fafc;} -.w3-theme-l4 {color:#2e5473; background-color:#e4edf4;} -.w3-theme-l3 {color:#2e5473 ; background-color:#c9dbe9;} -.w3-theme-l2 {color:#2e5473 ; background-color:#aec9df;} -.w3-theme-l1 {color:#2e5473 ; background-color:#93b7d4;} -.w3-theme-d1 {color:#f7fafc ; background-color:#6195c0;} -.w3-theme-d2 {color:#f7fafc ; background-color:#4a86b7;} -.w3-theme-d3 {color:#f7fafc ; background-color:#4075a1;} -.w3-theme-d4 {color:#f7fafc ; background-color:#37658a;} -.w3-theme-d5 {color:#f7fafc ; background-color:#2e5473;} - -.w3-theme-light {color:#2e5473 ; background-color:#f7fafc;} -.w3-theme-dark {color:#f7fafc ; background-color:#2e5473;} -.w3-theme-action {color:#f7fafc ; background-color:#2e5473;} - -.w3-theme {color:#f7fafc ; background-color:#78a5c9;} -.w3-theme-txt {color:#78a5c9;} -.w3-theme-bdr {border-color:#78a5c9;} -.w3-theme-d5-bdr {border-color:#2e5473;} -.w3-theme-l1-bdr {border-color:#f7fafc;} - -.w3-theme-hvr:hover {color:#f7fafc; background-color:#78a5c9;} -.w3-theme-d5-hvr:hover {color:#f7fafc; background-color:#2e5473;} -.w3-theme-txt-hvr:hover {color:#78a5c9;} -.w3-theme-bdr-hvr:hover {border-color:#78a5c9;} diff --git a/css/gauges.css b/css/gauges.css index ed4068b..7d46af7 100644 --- a/css/gauges.css +++ b/css/gauges.css @@ -4,98 +4,105 @@ */ .gauge { - position: relative; + position: relative; } .odo { - position: absolute; - top: 67%; - left: 50%; - transform: translateX(-50%); - -webkit-transform: translateX(-50%); + position: absolute; + top: 67%; + left: 50%; + transform: translateX(-50%); + -webkit-transform: translateX(-50%); } .gaugeSmall { - max-width:181px; - max-height: 181px; - width:100%; - height:100%; + max-width: 181px; + max-height: 181px; + width: 100%; + height: 100%; } .at-gaugeSmall { - width: 221px; - margin-left:8px; - margin-right:8px; + width: 221px; + margin-left: 8px; + margin-right: 8px; } .gaugeMedium { - max-width: 221px; - max-height:221px; + max-width: 221px; + max-height: 221px; } .at-gaugeMedium { - width: 261px; - margin-left:8px; - margin-right:8px; + width: 261px; + margin-left: 8px; + margin-right: 8px; } .gaugeLarge { - max-width:261px; - max-height:261px; - width:100%; - height:100%; + max-width: 261px; + max-height: 261px; + width: 100%; + height: 100%; } .at-gaugeLarge { - width:301px; - margin-left:8px; - margin-right:8px; + width: 301px; + margin-left: 8px; + margin-right: 8px; } -@media screen and (max-width:550px) { - .at-gaugeSmall { width:100%; } - .at-gaugeMedium{ width:100%;} +@media screen and (max-width: 550px) { + .at-gaugeSmall { + width: 100%; + } + .at-gaugeMedium { + width: 100%; + } } -@media screenand (max-width:640px) { - .at-gaugeLarge { width:100%;} - } +@media screen and (max-width: 640px) { + .at-gaugeLarge { + width: 100%; + } +} @font-face { - font-family: 'LCDMono2Ultra'; - src: url('data:font/woff;charset=utf-8;base64,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') format('woff'), - url('../fonts/lcdmono2ultra-webfont.eot'), - url('../fonts/lcdmono2ultra-webfont.ttf') format('truetype'), - url('../fonts/lcdmono2ultra-webfont.svg#LCDMono2Ultra') format('svg'); - font-weight: normal; - font-style: normal; + font-family: "LCDMono2Ultra"; + src: url("data:font/woff;charset=utf-8;base64,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") + format("woff"), + url("../fonts/lcdmono2ultra-webfont.eot"), + url("../fonts/lcdmono2ultra-webfont.ttf") format("truetype"), + url("../fonts/lcdmono2ultra-webfont.svg#LCDMono2Ultra") format("svg"); + font-weight: normal; + font-style: normal; } -.ddimgtooltip{ - z-index: 2000; - box-shadow: 3px 3px 5px #818181; /*shadow for CSS3 capable browsers.*/ - border-radius: 8px; - display: none; - position: absolute; - border: 2px solid #2e5473!important; /* Changed to match d5 of theme */ - background: #f7fafc!important; /* Changed to match l1 of theme */ - color: #2e5473!important; /* Changed to match d5 of theme */ - padding: 0 7px 3px 7px; - /*font-family: sans-serif; */ - font-size: 86%!important; - max-width: 300px; +.ddimgtooltip { + z-index: 2000; + box-shadow: 3px 3px 5px #818181; /*shadow for CSS3 capable browsers.*/ + border-radius: 8px; + display: none; + position: absolute; + border: 2px solid #2e5473 !important; /* Changed to match d5 of theme */ + background: #f7fafc !important; /* Changed to match l1 of theme */ + color: #2e5473 !important; /* Changed to match d5 of theme */ + padding: 0 7px 3px 7px; + /*font-family: sans-serif; */ + font-size: 86% !important; + max-width: 300px; } -.tipinfo{ - text-align: left; - padding: 3px 0 3px 2px; +.tipinfo { + text-align: left; + padding: 3px 0 3px 2px; } -.tipinfo h5, .tipinfo h6 { - - line-height:1.2em; - margin:0; - padding:0; +.tipinfo h5, +.tipinfo h6 { + line-height: 1.2em; + margin: 0; + padding: 0; } -.tipimg{ - width: 438px; /* suggest 380 for wxgraphs */ - height: 175px; /* suggest 260 for wxgraphs */ +.tipimg { + width: 438px; /* suggest 380 for wxgraphs */ + height: 175px; /* suggest 260 for wxgraphs */ } diff --git a/css/mx-templates.css b/css/mx-templates.css deleted file mode 100644 index 906ff38..0000000 --- a/css/mx-templates.css +++ /dev/null @@ -1,249 +0,0 @@ -/* ----------------------------------- - * Styles for CumulusMX Templates - Last modified: 2021/03/19 09:23:15 - * ----------------------------------*/ - -html, -body, -p, -h1, -h2, -h3, -h4, -h5, -h6, -li, -td, -th { - font-family: "Rosario", sans-serif; -} - -p { - font-size: 15px; -} - -#Header { - border-style: solid; - border-width: 0 0 10px 0; -} - -.site-width { - max-width: 1140px; - margin: auto; -} - -.graph-width { - max-width: 1250px; - margin: auto; -} - -#Footer { - border-width: 5px 0 0 0; - border-style: solid; -} - -.logo { - max-width: 250px; - margin: 5px 0 5px 16px; -} - -.subText { - font-size: 80% !important; - font-weight: 400; -} - -body { - background-image: url("../images/picture.jpg"); - background-position: bottom left; - background-repeat: no-repeat; - background-attachment: fixed; -} - -.statusPanel h5 { - margin-bottom: -5px; -} -/* ------------------------------------- - * Flex boxes - * -------------------------------------*/ -.at-flex-start { - display: flex; -} -.at-flex-end { - display: flex; - justify-content: flex-end; - flex-wrap: wrap; -} - -.at-flex-justify { - display: flex; - justify-content: space-around; - flex-wrap: wrap; -} - -.at-flex-between { - display: flex; - justify-content: space-between; - flex-wrap: wrap; -} - -.at-flex-bottom, -.at-flex-items-bottom { - align-items: flex-end; -} - -.at-flex-items-center { - align-items: center; -} - -/* -------------------------------------------------- - * Menu enhancements - * --------------------------------------------------*/ -#Main_Menu { - margin-bottom: 4px; - border-width: 2px 0 0 0; - border-style: solid; - min-height: 32px; -} - -.at-slim { - padding: 4px 14px !important; -} - -.at-divider { - margin: 0 5px; - color: #f80; -} - -.at-spacer { - min-height: 2em; -} - -.at-menu-lable { - display: block; - width: 100%; - font-size: 13px; - font-style: italic; - padding-bottom: 2px !important; - padding-top: 4px !important; - border-bottom: 1px dotted #c2cfa5 !important; -} - -.at-menu-bar { - display: block; - height: 2px; - padding: 0 2px !important; -} - -.at-indent { - padding-left: 40px !important; -} - -/* ------------------------------- - * Model enhancements - * ------------------------------*/ - -.w3-modal-content { - margin-top: 10%; - border-radius: 8px; -} - -.w3-modal header { - border-radius: 8px 8px 0 0; -} -.w3-modal footer { - border-radius: 0 0 8px 8px; -} -.w3-modal .w3-btn { - border-radius: 0 8px; -} - -/* ---------------------------------------- - * Media enhancements - * ---------------------------------------*/ -@media screen and (max-width: 780px) { - #Footer { - position: unset; - } - #Content { - /*margin-top: 170px!important;*/ - margin-bottom: 5px !important; - } - - .statusPanel { - text-align: center !important; - margin: auto !important; - } -} - -@media screen and (max-height: 768px) { - #Footer { - position: unset; - item: center; - } - #Content { - margin-bottom: 5px !important; - } -} - -/* -------------------------------------- - * LED enhancements - * -------------------------------------*/ -.at-led-round { - display: inline-block; - height: 1.2em; - width: 1.2em; - margin: 0 0.5em -3px 0.5em; - border-radius: 50%; - background-color: #888; - box-shadow: inset 3px 3px 2px rgba(220, 220, 220, 0.6), - inset -2px -2px 2px rgba(32, 32, 32, 0.6); -} - -.at-led-block { - display: inline-block; - height: 1.2em; - width: 1.2em; - margin: 0 0.5em -3px 0.5em; - background-color: #888; - box-shadow: inset 3px 3px 2px rgba(220, 220, 220, 0.6), - inset -2px -2px 2px rgba(32, 32, 32, 0.6); -} - -.at-led-brick { - display: inline-block; - height: 0.8em; - width: 1.6em; - margin: 0 0.5em -3px 0.5em; - background-color: #888; - box-shadow: inset 3px 3px 2px rgba(220, 220, 220, 0.6), - inset -2px -2px 2px rgba(32, 32, 32, 0.6); -} -.at-led-oval { - display: inline-block; - height: 1em; - width: 2em; - margin: 0 0.5em -3px 0.5em; - border-radius: 50%; - background-color: #888; - box-shadow: inset 3px 3px 2px rgba(220, 220, 220, 0.6), - inset -2px -2px 2px rgba(32, 32, 32, 0.6); -} - -.at-led-green { - background-color: #0b0; -} - -.at-led-flash-red { - animation: flashR 1s infinite; -} - -@keyframes flashR { - 0%, - 60% { - background-color: #f00; - } - 61%, - 100% { - background-color: #800; - } -} diff --git a/css/w3Pro.css b/css/w3Pro.css deleted file mode 100644 index b8b5b0f..0000000 --- a/css/w3Pro.css +++ /dev/null @@ -1,247 +0,0 @@ -/* W3PRO.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */ -html { - box-sizing: border-box; -} -*, -*:before, -*:after { - box-sizing: inherit; -} -/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */ -html { - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; -} -body { - margin: 0; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -main, -menu, -nav, -section { - display: block; -} -summary { - display: list-item; -} -audio, -canvas, -progress, -video { - display: inline-block; -} -progress { - vertical-align: baseline; -} -audio:not([controls]) { - display: none; - height: 0; -} -[hidden], -template { - display: none; -} -a { - background-color: transparent; -} -a:active, -a:hover { - outline-width: 0; -} -abbr[title] { - border-bottom: none; - text-decoration: underline; - text-decoration: underline dotted; -} -b, -strong { - font-weight: bolder; -} -dfn { - font-style: italic; -} -mark { - background: #ff0; - color: #000; -} -small { - font-size: 80%; -} -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} -sub { - bottom: -0.25em; -} -sup { - top: -0.5em; -} -figure { - margin: 1em 40px; -} -img { - border-style: none; -} -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} -hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} -button, -input, -select, -textarea, -optgroup { - font: inherit; - margin: 0; -} -optgroup { - font-weight: bold; -} -button, -input { - overflow: visible; -} -button, -select { - text-transform: none; -} -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} -legend { - color: inherit; - display: table; - max-width: 100%; - padding: 0; - white-space: normal; -} -textarea { - overflow: auto; -} -[type="checkbox"], -[type="radio"] { - padding: 0; -} -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} -[type="search"] { - -webkit-appearance: textfield; - outline-offset: -2px; -} -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -::-webkit-file-upload-button { - -webkit-appearance: button; - font: inherit; -} -/* End extract */ -html, -body { - font-family: Verdana, sans-serif; - font-size: 15px; - line-height: 1.5; -} -html { - overflow-x: hidden; -} -h1 { - font-size: 36px; -} -h2 { - font-size: 30px; -} -h3 { - font-size: 24px; -} -h4 { - font-size: 20px; -} -h5 { - font-size: 18px; -} -h6 { - font-size: 16px; -} -.w3-serif { - font-family: serif; -} -.w3-sans-serif { - font-family: sans-serif; -} -.w3-cursive { - font-family: cursive; -} -.w3-monospace { - font-family: monospace; -} -h1, -h2, -h3, -h4, -h5, -h6 { - font-family: "Segoe UI", Arial, sans-serif; - font-weight: 400; - margin: 10px 0; -} -.w3-wide { - letter-spacing: 4px; -} -hr { - border: 0; - border-top: 1px solid #eee; - margin: 20px 0; -} -.w3-image { - max-width: 100%; - height: auto; -} -img { - vertical-align: middle; -} -a { - color: inherit; -} diff --git a/css/wah.css b/css/wah.css index 950fc1a..2f75a36 100644 --- a/css/wah.css +++ b/css/wah.css @@ -1,44 +1,44 @@ :root { - --background: #f2efbd; - --background-dim: #d2d0a4; - --foreground: #2a271c; - --border-color: #f27405; - --border: var(--border-color) 2px solid; - --shadow-color: hsla(11, 96%, 43%, 0.4); - --shadow: drop-shadow(8px 8px var(--shadow-color)); - --shadow-small: drop-shadow(3px 3px var(--shadow-color)); - --links: hsl(183, 93%, 27%); - --links-hover: hsl(183, 93%, 15%); - --table-header: hsla(11, 96%, 43%, 0.2); + --background: #f2efbd; + --background-dim: #d2d0a4; + --foreground: #2a271c; + --border-color: #f27405; + --border: var(--border-color) 2px solid; + --shadow-color: hsla(11, 96%, 43%, 0.4); + --shadow: drop-shadow(8px 8px var(--shadow-color)); + --shadow-small: drop-shadow(3px 3px var(--shadow-color)); + --links: hsl(183, 93%, 27%); + --links-hover: hsl(183, 93%, 15%); + --table-header: hsla(11, 96%, 43%, 0.2); } html { - height: 100%; - color-scheme: light; + height: 100%; + color-scheme: light; } body { - color: var(--foreground); - min-height: 100%; - background-color: hsla(0, 0%, 0%, 0); - padding: 10px; - font-family: serif; + color: var(--foreground); + min-height: 100%; + background-color: hsla(0, 0%, 0%, 0); + padding: 10px; + font-family: serif; } /*noinspection CssUnknownTarget*/ body::before { - content: ""; - position: fixed; - top: 0; - left: 0; - background-image: url("/images/background.jpg"); - width: 100%; - height: 100%; - z-index: -1; - opacity: 0.8; - background-size: cover; - background-attachment: fixed; - overflow: hidden; + content: ""; + position: fixed; + top: 0; + left: 0; + background-image: url("/images/background.jpg"); + width: 100%; + height: 100%; + z-index: -1; + opacity: 0.8; + background-size: cover; + background-attachment: fixed; + overflow: hidden; } h1, @@ -47,7 +47,7 @@ h3, h4, h5, h6 { - margin: 0; + margin: 0; } p, @@ -56,136 +56,136 @@ ol, dl, menu, dir { - margin: 0; + margin: 0; } hr { - border: none; - border-top: var(--border); + border: none; + border-top: var(--border); } a { - color: var(--links); - text-decoration: underline dotted; + color: var(--links); + text-decoration: underline dotted; } a:hover { - color: var(--links-hover); - text-decoration: underline solid; + color: var(--links-hover); + text-decoration: underline solid; } div.page-container { - /* width: 1000px; */ - width: 800px; - margin: 5px auto; + /* width: 1000px; */ + width: 800px; + margin: 5px auto; } div.page-container > div { - background-color: var(--background); - filter: var(--shadow); - padding: 10px; - border: var(--border); - margin-bottom: 20px; - /* temporary */ - /* height: 600px; */ + background-color: var(--background); + filter: var(--shadow); + padding: 10px; + border: var(--border); + margin-bottom: 20px; + /* temporary */ + /* height: 600px; */ } div.page-container > div:last-child { - margin-bottom: 0; + margin-bottom: 0; } div#header { - display: grid; - grid-template-columns: 66px 1fr; - grid-template-rows: 1fr; - grid-column-gap: 15px; - grid-row-gap: 0px; + display: grid; + grid-template-columns: 66px 1fr; + grid-template-rows: 1fr; + grid-column-gap: 15px; + grid-row-gap: 0px; } div#header img { - filter: drop-shadow(2px 2px hsl(0, 0%, 66%)); - margin-right: 10px; - image-rendering: pixelated; + filter: drop-shadow(2px 2px hsl(0, 0%, 66%)); + margin-right: 10px; + image-rendering: pixelated; } div#header h1 { - margin: 0; - font-style: italic; + margin: 0; + font-style: italic; } div#header h1, div#header p { - display: inline; + display: inline; } div#content { - position: relative; + position: relative; } div#content::after { - display: block; - content: ""; - clear: both; + display: block; + content: ""; + clear: both; } div#footer { - display: grid; - grid-template-columns: auto 1fr; - grid-template-rows: 1fr; - grid-column-gap: 0; - grid-row-gap: 0; - align-items: center; + display: grid; + grid-template-columns: auto 1fr; + grid-template-rows: 1fr; + grid-column-gap: 0; + grid-row-gap: 0; + align-items: center; } div#footer div:last-child { - text-align: right; + text-align: right; } /* -------------------------------------------------------------------------- */ table.almanac td:nth-child(odd) { - font-weight: bold; + font-weight: bold; } table.almanac td { - padding: 0 10px; + padding: 0 10px; } table.almanac td:nth-child(even) { - padding: 0 15px; + padding: 0 15px; } table.almanac { - min-width: 100%; + min-width: 100%; } table.mx-datatable { - width: 100%; - border-collapse: collapse; - border: var(--border); - filter: var(--shadow-small); - background-color: var(--background); + width: 100%; + border-collapse: collapse; + border: var(--border); + filter: var(--shadow-small); + background-color: var(--background); } table.mx-datatable th { - text-align: left; - background-color: var(--background-dim); - border-top: var(--border); + text-align: left; + background-color: var(--background-dim); + border-top: var(--border); } table.mx-datatable tr td, table.mx-datatable tr th { - padding: 5px 10px 5px 5px; + padding: 5px 10px 5px 5px; } table.mx-datatable tr td:nth-child(2) { - padding-right: 40px; + padding-right: 40px; } table.current-conditions tr td:nth-child(odd) { - font-weight: bold; + font-weight: bold; } table.current-conditions tr:last-child td:nth-child(3) { - font-weight: normal; - font-style: italic; + font-weight: normal; + font-style: italic; } diff --git a/images/CumulusMX-Logo.png b/images/CumulusMX-Logo.png deleted file mode 100644 index ecf0246f86a1ea9e2c9c1049779d8bb3e372c919..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22972 zcmXtA1yCE`*9{)rDaGAgN^mV&ph$t@1zOzQ-HN+gad)@i1^UC?wZUD2f9Zeb%gk_Z}#k2)^WPT#+|SlZiBXA;ZyOMM~!n2kG!I~0b6L+;O_GaOhS&GU<3H9*lZ z8dC-rC2RxF3Z5@!Z?Tnm9n(86|7Ja%w_P8)^zg49J}6H3T(2TeKufRvp8Et;bz4gRmMA1u7c=Mj zBd{Hxl3UX9b{Iyf`)#?p{N+um#?gqbrxlI7Dw;dgWWZCWa>$UMoM7H(&H#SLB1Zjf z#a;!wm9cs21)23qEvzc``~5_(_Oeq9^Vj-E!&*+C6-ebk?ASG_4c;jjZ0jy|lzr9op&-gjtMoj_S7SBMNXUF2m$cG3iJ{gsGZk{2 zorb(*Zxj19cgx0TrlPsP`pY}?+^os$@H5lpt09Y12Njced9noymS&P~nj_NrG4u=E z^Ij=j7-~}S|CNrGXvj+_Dv(*5oB~kPx4kKV4inUl7AQIh@>R{y@&FeWC4!F@_`A^z zgdRoCISfhX&$l=4QQl6j-x)lcgU_Z>ZD!2gO%qHma${j}-ebSW$}~q>FI1UqXvAIb z>_EP@_@M63R|WznwRKp_wU3GM3zNe&;US2+pt^jKNC%1u%aCL$-y#4txe!lCGs%Kg z^k)#84o<(cV!YJ0QXno4Y4ALWDoYntD4;G?^MmR)vp$s!H}Dv@eY)83z`5A9wztPo zCg1Wt-_Z4~(#TqAo|kc->HR0879VEo1-IE=H}-`9LJAL8dEOr-zZ&GiL4=9ao-2QK98vRB%>+Zvd_Y zslP(Xr9x^T^=G67IO~9q;A-%idO6wYYr?sYpXX-M`Kg}6h__ z-KxkVLNZw5`bK8zSX3kh4Cl{J&?&t{0-1t?G>C$ShOx*z6zR3hR%mlZahdXTyC*(( z%aVmJf#`VP0|%}N1J9`widKi?Rm`7etI6GS9IiUwZmaOIy**VYwUZb+vqV{PhfE3p zUF05&4s?+^EUz@FzZ}b!4(4wEUhNJ0=OO9?=AwrBXTkSM#aHKH?VBh8weY7g*BB1g z<(gvt5YhRG0{{IT-b#c@2lZ_(V#HxI6Sg)WHJ!TRFOaM;u&5stK2K8alZ+3=ik=_j zsOQ2}*c#DJiEKXd*tIE^dpIBj_cSMZ(^|3ntobc# z!sXBF-%v<*Qz@ieAxU(|&Zy;G6cQx}00lX)D8v?EM|@)FJlG1x)^pxV;GJ)>oYlh; ze=ZwkXRof#>R7niSL#$OhAeJ)9oKq6CjD8uo%VnFRyW(yEm&e-_->UJt9yQ|*MX8< z*waOBlKyl=T)XhXn<9l&XR7;Nr7}Kt=Gv21gkpSQk*Sxo4vsbb#Wko9=@6#dtYSc# z{8@+kQXfMKj)d9A1QR)`4<|wf^g;!OcO*8!E#i5v>+C5)U*A8V0jG|Z4ZnHqxbREl zBjop`ne3<6nIX#8(($_+GJea3(q-G7uWUr>;7f2Zn3|4;f$>v1-@WL$pj_|U3#Fii zvs8QYpIqPF>@2$u4#T>wj6#K~aaXW?fOApuT}|g-Ee4e}>u2O$Cvby$dDngHhPV0U z?CM!((c{cZ8s=Sffqj`u8NXv$WFg7Q;GkNxE4(@Xt=A`Z6*g%jFX-4#)eu^s#5Z!{ z!uo|RCCbet5Otl@7HT9V6uL~-lN_^^7*1)XP>c^3lVf)B+p#J3eP`V-Ar3*PZ|SBR zJRkmY*7JI!Uh3(P$u{v8+7=b~TBP@QHt+SMAIkU@fsW{cVUWXXPhZKY_@9N?*@iZ*Z z!>B59S@gd1q=b|k1mbd-5H$aDerA}FC+t2=D&Y4LL3`(0(b@{Z1P`j0ul05gH#7SQ zK-y;)|2$o@zwGZ@l@amqammrcUVwh>m&LNZJfx| zhc#|Fa#x$TKN%zDDuVktPqudLo3Lv5__Vp{{D;VnIglHiOQech11sg-_Ax(Ws4@6; z(X)9$=6!*E)O8?;!vYneyy~|cWHx5;&}1BvsD?y3XAP=Qct%Mk8n(drq9BYzn^dss zw<)0IsF_pIGl66UVaEH1WB&*6SIUh6=b56>c z@y_1~y&fOS#oNU<1Ofyb3raC<<5~BpF zqy^hIGU`wOGYl|%Vv$&oGOsHnHK5YV+Z)U4STBya?WBSAuT6DSejq@obsL&9 zA$|SVsLpG-A7Q{tUUX)zF#b2m&hM?J;cNAPa2(iO6~u7$|B?w%N2VtPg>&O3Bmv>D z!b{1tfKvFl%XHjg5R@Vf=IlBTLjdTCy}C%l5?)++@41;le!ZCyQmBx$C@fr@=mX2# zL=HL0Gk-E&M+fxqCX8N=N(95nwfNA9M4Sog2t3|7$d_xr4wr;DJ0~md3kM#8ix+gy zql~%^F05-`&VpARP*I~-7oN`83~QV;7k3`=4h`F*y^3J9s0zu{wvd2~$p{beP=Y|$DSk&y>tPksre>oHE?;4Bfj9F!;Y z+#6W_St>ypVsUtouS-sqW=)%d1q{OIc}F!{of4QSbbf_C@iV$|K!kTld7|%P@-(WS9S0F95>(az0ZT#4q3u4 zZ6m&%Qr#~FLHxMw&)$@ek4eGrQ75R1B$o~$qFpv*`BIH&67k%Y1lqa<9+Np@Gb#mh^&)lVE=_db0_cLa znBy7c9ascL?zBhTqW;Ah2(3zP;PJjYwQixy<~65SnveMPh779FWSQLD@V1A|=w~tq zF&y6=e9Ck_*vzjB)j*8gbZu>LIGm}>^V+My*Qz<9Nf}F2^hV6!Q-4sPV4%mNM2! zyZ!iKOKxGM(3rmW--uFwBdaA(h;I__lKcD>)^>mV_)wEQ_{n5^EIveBb$2C4D zf#N<5O%4>A1xElfQYCL|qVFyZ z-!(jq`QM9=C;OIem%@i!C=~kyxd<&Mmct{Diog2AK}#z+#k?==Jnmp~^~Vy!cw@cu zL7c=k0wwhKi=LvQ`289$M1XB#6Ogx>(~mmUwkZJTd|2GrLWjkUS-(y%@-%bh$p0To zg`>}#v+Bm%XmK$T5Q6(YYIrMz?lWBOJGzvu;&8Q?JK}`lAq5rlhP3rxF(tYJnn&Er zO{!v~IM%^mDAbv&G@4psXx1}Ll|37lwaWPs!-<@yBe!>&s@Z!)6fDBpLc2B(XM>D1tXM=vZN#n8#EJ*1^Gn zPe*I3IojwrA z$8c38{`bS;m^czAk?`1R61(F>uI719ICnY0+{bhO=%uKV{3!YDV8e7+;A7k9Cg!S% zta992iS2yMZvMGBkAY5uU z!bF*jG#VFVo4`~Q-*!6`pCi3m)EfVJE4o-0yFA==Mlw_XgS1X<{)L6LWgj{$I|!D1 zS`LSmylK61P6Pa6|5D+Sp54Ujjmv{O5tI9sBfrYUDzU~&>mh6ryG;QeISiMdH_$!Jh#Rq_XrDm2+|!rA^#bcI20nMo zkeYir2fPhq2h>w=3)1}D zx#Rj-Hg{BYdRp3RhfT2I+<$oJ-Bo1-0NKHC}KW4k&Lz<4xg=!p89>8 zb#Fm<;t)=EmjK~NakzO%p1<9r11E*cRNpNO%qX;c?n1;Hzp8|-nq%%Hxyr!6iUZW$ zlR%AO7zr?+$mX|`SuIMgmAB%0E7tLy?4Vei^%n2INzNG}u;nA&tCyKO1 z{flwIcZM$;v{`CT4F1a(&K{Qv9V->qH<4|DV&Sje@jULGe-igi_wL}kQ*7eVzKmPU;v3_zey{)75-i9h1) zo&?RvIzjw7)c*`U?doUZp;#fT?jGpe*e|RlcM$LQP0%V5Z)!%=Suj@ z-qKRk&l$zg>#&Nkx_Km?ZP8tK>pSD6+*Zt@f&1wgYwh!B<)HImL=e?sfu@hw2Cp23 zChJr9unOh+H21@ehDvtw#E-jo5!vUJMK`1YN~yaO@1vDgOuDW}@ahH~KN%Tu&U@wP zi;dhM+{pp^`ajb9l*iXo6TpW{gQ6NUbx8GXfYsD3nIJd$T^w~P(PcK7{cOMkg0<#74By&WhNi!?uP_HqbJpyb>@8(=uSlT7abgK`%ep*1HFD6i$F3D)io7 zQG&GJld?{GS8Ua(R@u`0MY^*$Ru z`d6chyT84-t1dyCTYGMkgI^*3et&aZW)9DDg}z^P(pKvE?kA~~ezt03cG4-0{1xHF z-jBPBM9~A;eS%X5?kvqLu8#lw!WwB3oD^F}#BKMCh#X$Qc78;2;e$v;9v~?kKOnd2K}daxx3YjQLU7q!qT22Xk-n#`c8Peg znRWs1h~#W3q0jdcc3a>uYj^?EiI#EvWl9yCkk?C zKaiLw>d#FPYt0WLbl!13xDS#jK8leI(ebc|6q_Cee8)tlD|OpjPkWw9VNbbcKX zb31zluLdZ8%{zx5&ht8Yk8QInVt4nb*B~N}ZKfjjKptmXJTHjfR-wsqZ#NEb|6pKH z9II<4D_0LH=g-Q?9N!nF@bP#xJQqDaeT8XGn_PT+2gt~eL*(vj!`Xt^j_2L(ZZ0k^ z4KRw={KM&Mg9(&#R%b*rEDTsEBso^tS{i57{5s}t&yhrvH%?XDuQPh&YW=mbCb}^Z z6iZA@CPO;VR&QD+i!1%|0;NkWbrs9iq(WTz$}=YYldd7w6{>C=DuoEw58qE6qKHN& z9I1|%JgAKpA|vNIwM}|N;}e`VIV;2?C&v*S@r2riv4F6PsAf|Z&L3^J7q2T>Xd#-L zC-s0CrK^}-588Dgu1boKB_W)kE-J*cu6UWwtr>o69fS)=7rci4X~_jS|GmtR?aL}$ ziriTSQuw3b2&`RnE)vsZ?LI*A^m-c|d_UjG1o+;s*P42dI3HK{9?^e2v*!SIU{kf4 zQ;;qS3>f$)2}l1Nk`lgv=h`{zq%>+Sh97u36|l=#aAb9mDAzn&S&%$q!cOzLk|PvW zB~rkKA_Sm*BOp9#W|5W-)F=|**2)1oQ7Gb_LOS~`7iBrcr z6ck~0RH3OF6b%0yl$y%7D;sC_Cw;oz-UAWBi(|AtV!Dp+zH;4gOC#CvY-60ts*iR=j%;vBz=GXO*3m- z);dH`u_jAzT_krN{2E4+0`t@A%1YX&tPkC95b?KDYp3}%PNNmqQTlhBeyDk-a%E9I?<|szp&z%IN zFU8_(9nIFBTkiy}2WM3qKFHJRUYV)Gkv|ZL9O4#fAW8--aO=wLT?-D!kgASN;w{JP zR*z-QTRSf7Jc%Kspru%m(@S_IS``O5V6l?*SE&ZM)6qvu?tJbKbkI4jll^7Zpecuz z?81aHEC`lU0IQOK1ren@faXcN$#NgEN*fDfT!g^bh&_2UlSc^ z)EYusi6CqX^rpN-O#o9o>KId{W(r*E7}r>^DlY0Rx6s2yCoqe z8kINeu@Rk7eH~_{VuzK5c{>$>D-`t`{JZX!| z$%NT&r@iIfhn1f-g!a9Va=8QDJDPP??WxsPqRJ%fo_bg#tX^T|)~%&EY4UFbjWV&^ z&Asb&AGWU;t_lh#yIy}H;rPSLmqmw3U-zW56Jt$1lv!1wm?qA872{CaXcHP!;4!r$ zfqLaaxu!JFAx5*6jE$*P3U!m~sG9=$b~gA?jGJA-6}#t6pI9mILaIOQ!X>bKu|?g>6=AT;vDle z#UJ!Z$!&AY8U*_#Oq*nBlDIo=;b_noOseIwiS`|=z~vtl9XjC|3k_?@YlAEJ^YWV`&2s!7qP^sb{0Jcz~jT=c))oBd-58bq9(Cy82k zm+b^?6gt{0DgO}>7hz)uLQYw<+sxd(^t16y?d z-qt8E3Fr-`8*(7prK)4SKt}}31$)vP@q}cOK+WE}3{Uxr~#K4n(AtXSqh`b&( za;GS`=mJqb96~l6*hd53_xTMlLg7nhFZi$y5V;yOeZE`JE7uO!nco};iS$mexBfo& zI-3Fd#s=$$mWR52qL+<_K8c_jN0=(x+sh2$D=aFZD<(u#&ol8!AsW-bo7cgbA6TaJ z@=;Oy zqD>xjYw7C<6olmYKF@aUieB8ymTT4s=v%t=zF>KLi5%+d3k=+@0!w3y&amlRM9bk3 zZc<;e5uw{7{eTteiKjhA^KP2#@iflUl_f*lqiEe#1A~965 zjn!4>i*@%m&kcuWUa{*8rQuxHg;4+{3lX|@n&SS7R_q&St2gk^$9KNlqnJ@G_Eg!G zf$n@(@b(GH#qYC$P0^$R-=fy({w304R}r{$*fd$R`%l?DWJD{>{&BfV<1BgJHSc+s zUEIF?ba7G5usxY+LGuXL`l<5f2778zU{IoY!dR3B1G8B-r_U>AqvMBx*+Jz98J8u` zySL--Oq|A47>Dmq%>T4G?ybu5Jc5HWoK760g&dF{)C#{gJ0Z=#O1co6Bs%b7MI~Vw zdC5x%DwD~9m=zxKll!mfdJxM+ip(!Vq!mIFiC7VPLL}sqH9cme6>6uY4Yobui@_RH z-E^58DKhfdjED`>lDw7#a(KVF6@*Qwk<^KCNT}KRE$WEO`98!tFi4GrF;$tmMmOM9 zVh#_>e2b`AEMK$^xg{x>o@**GtW_hgsB5v0KXVnWIy)`!wx!&6^-V^xlF<$6d^~@1 zpTLk%&bYF2hnU8RUR^oxTTg;^tLo{-w}ajLyZtfB?0t5~k3TlkRvh7aKd_2__9_Z2j92lU%D85c{=}!_#8m3=eZ# zBy+IX;dud#(MDHf6WQb3b5hVt>7B)=Tx5!kl`K2XC=}00!}fzX^gNHPx-360`ZzHc zf#xaWoP3JVIa(#rD!d`?dPgQ^913F7a!a|mtAw7dtxvhwnDSyd@546*24~|$#@H8) zCSQ6V*^4{RP3x@RmwX7(NVHL+(5}S`rOt%`@kDSMVlLGMU2d{`xf+jU&0hsdBf3|G z={kZW%D_6hzIO?1qX=er0c!BnNq3~cDCyl0Nwmm#63EV=ej7^|+f+{9ENx9~$@$TmAv{fG z8;QdB@R-!(u!2WPtL8iGiL;ih%Uin_<#oanfhtb$FZ2%6-}4`+dzsDi>vh--Hva>1 zsYrGLFu?>&+gQHZQkYH*|HRhdr z^VnSLyWO)L`*0a&Kao(C$!S@YC?IgRD=+leGWk!_9{@r=;h{gY!TOrY)guD?*CH74 z=N==StvZ`mlm4#=bUiWNt^32PW6xp}D)*e753h1(pH;(ZDHap)fHb8M zq=e?t~O!+b#cQb^1#fRUm zIH+NY$IH)JG$Did6y-$_r9e2y%zc8WDkgBu@;-?`IwE$Y{%M`WBw&_{!p}G-c@!z3 zDtzGKg+C<08{z6=AkJ$Za=cR- z_RVL$qJ|77Nv7Bh)&2Go`E97Q*7w^)p61~L1UL}S6-y$SN3x<@q|RjSI6=FaICM{- zYn>fm28Q_hx|WDsVcg%|ai^t!q-%x{Os#B;WyOKAeK(y%WQ)odk#QNm?$BUJF{s&~ zMt)?bkE}n%0fr!ETNV+O@9CgUp!%RlEr+!U6>%}qsR!V<)Uz_9!VA*JtI#hLHYzxp zW!Xg9*tp8ky-6&|be%q$p(gA_C_?Hc@Mx!8gBM0C6l(Pb%A^7l@JDD}Fsp_Oz(J|V z^z6Do8>&mTEfGze_$v(^=E&v(A&?BqOi?g_6lg|L!dgrzkI3EkFJ zg^mtwaWVqTiBQ`h(%Gr~7q($}Z>Y(UulmC%s~276s4bD|78;fJ81s3T|IT1{tkK(e z6vv~5uHy2)7H!KVDyH%j*eyjE)(23688Mm{R=(yv&V`5Bn)=OuS)}w?`Zh#ueOd}T zbX%{kqk*a;QCbn{CokqNKX|3GWw3L8 z66SVZT>AR-Aose|4t;=>EesU(cf`WR$I9ZfVxo#?K3#5_6q@AN{q%xK$X-stu=kci z&-~)ZwZumWZ*%k{Il=?t<-XtCNGq~2bQDMQd6P;1d8O+VR)U@ zKS4#VfTB$8s6yul+rx9k_@iSN<56qV%Bt1J-dV{*+SKMMsQZNw(FzF0G?ThkA^4wUxO&DCZZpO=2jIwRT&^6=te1^3vWDy@~ zLj~ad^z^(VV|>zM=5oGSx`f{b47A>c!D4B=^=a~2`}wKYACf{Iwy5ts6b#ct(_s~) zlyujNFy^v~BW0|z$pZDZ{#s(NGPBINVhiPX1I_E|(R4@zZN7QnPf zvxek*I*GwYHj1v-5TAGV6^YXT`cq6+Zu+nJ*95l0vEpNGz~_tyg{(Q`n2;*@^xYxF)W8L)`ad>~FL36d zpr9bvbX{f5!nwox>pdlYL&&?HmcnQEXfY(wWz(dEF`BlHY@5 zh&v&?SrHj%4QvMU1HXpG56-GhyYBD|J4Wu2-f!YEg)?I2B7{;kZ{$S|;}ex* z^bo|zw|_Lg$R0wilNb4}z#PaZl8nOy#;1e)r2BP-9?yYn9^d~hRHFU1XNK<508O6t zqIg(?h@K2q^7q>uihSi1K|Ur$(Fq+YA5M9%;txf{@6`<39t1)}5vmNEB3unvQFn<; zB?obTl*QGxh97lMupqo>R!Zw=NOwf&E7sqa5y2Zx+c#q06bq?7EtF2K5QZ|^QGLDh z#RmPpex4V9-j10}R{ZYyu>W>TJX&GVc_;mr;sn?_h3Rm$y6hafO%A>e!=liw?poZ& z)YOFqn3n=b3>)m04r!Zu9S{P@W_PY=_```C*iIxhX1H;kXx$5@9n=Oqba#vLewdef zKB}xehlAfbhAmKAI;4P=5BOxd$X&j2Y!kN_tu~vaIOf@xxz+3TM*%rKc@JlVWE33! zSJ#z>9`Mzs&o(6A*d41Cm1sBz+kV5q4G2She!#lD7Zj>^_A+XFOJY+Vnk#{trYa9~4-fsMIj?eyG<>P}faR z>GNz9v7sn{fx!e+*+bSvEbmu=KOzS)0l1PZp`YOt!!hP7+PI`}>VIrY5pkTBT=#@e zBlwbe?Vu8DJTp9}5((X9MBfm0Q2dIKO`sdHJ}xMVDPHc{{{k z!|3&D(a8CKUtrg{_+yr+sH9irF>lfC%ugktqTB&9=fojMfhjp=Hi+Zk4Dnw!Rm9*$ zT>6kGk968Dn*G-CRYfdi<>Vk5u;D{VKn$PJ`{sC-?8ZG1X`X6puh7*fE|IJE0U~^y zDwYtN{cSJ3eok8X%{WDikV+F=QIi59#Usricu(~CjFKwWL|0c>9@2n;6(-{-BZOwD ziZmC>@RKjM6lVtas}g@S&IFI$2}l;!4x2~3O>rC%H@qIYwqG|Eu?`%cc&u%H^K5$> zecyvIiI$zqoJ|g?E8^0D)WsMl;1JPcOwcn+X`zXb&@j^jXP1I91}}2tc@W6*WeS(_ zapbdr4ap^HuQm0o3P1PWFfH)$Gl0~H6nM(f{3PFyT!kYbNKJd!(QHKJ_qPcu#Y_IR zzHR$@+Vy7pELIY4wynH}cdLiQqM0v~LP=`jh|AH^#@`Y%^W8-BY>MxLnrLbi#(aI5CPxH6lF7~;xrQXWG&SRv5hTQ-x?(6& zX-Y7h^YU>8oJ)Ft2whx}1nCTw2tNv;YuqSbBec@sQ;o3y|B?f)j=zW&0MfODfqtka%}wE09${*Xm1?kIwi5fTMUz@n&Ff#>cCz}e%Q~E7#P+AG)u)>JIWnz(Kre=N+535|hIrsO#-yGL&tlT7 zfwOKpn-7r}KGl-^TwLGb``dC!w~mQF=29Wzaho5-dg7RC{}1{#%ECV{bc1oCmN-CrJ&!+;H95BZ@sLgQOt91c#d zVHngSuDlEh=cbBgNK+|X5e8NU@6GYpFg28!D;&+ zW$FpZrqAanrYH2o3`4cdaZ6$^Saipl`@IkpBR-?2A@DL&u~6AWH92N6u3PMy!ObC- z?|cXu2kK9>Q-Qx`Cnv~S1Usp>O_@ANS^qV^Hr*+V13~d^t1UyXVWyrCN11LSn$Q9C znG^qmPbHL2eD1GM#xG5wJKXmHMkaB=%QaETj$HqCKknk|zJC2>2 z&?wN$P+ErPbT1o$-w(@bt#Pc3t!4V|tG_w7_Zx^&*3C!JCiMU?^b#Lpqa)BzUugRc zW)t&Xo_3+ziXrB{;urf*w)j^uou&LNh38%%A!(F3?bn_~UE!0oX;~k93&H(lcdYE=PCwV};-GtQHu*V}sb-B0{aM*=mo?FmDk z&l9>8_P@1SDK;?RJz~yHy}yc{=VITp`Ij_zm85+!Fo0$Nc8hg7%-(mubVCm@m=6nM zsG2hCNYv4-p|rffLy{pjL|0PAO?cTPMI;N9;kn4;;OIP^qE<%mIax1T<6@vu&tD_) zmqzmU*I)8P8quaRB(a+jU(et>)s^0SlVJ>aGUzd`CIYk#I zE>!%c!_>7WMs|o;CD-@+=RWxPSV9L|k72zwe})3-yc;M18&4zRuXfI(S5GkfEDeik zov=Sixx(9)r{7}O{@iZ31oO%b@Z z?;jtnMH=_MYNd59n~(X0xDJ@ciH{yQ7Rr}8X;$!~(XNhu=e@ZP2W4qWOnQ0xkO{?( zwl-J33>wWbkLY_D^W%VB6G+4clQDc5; zX{v2dBcMe>>`_D`%}Vzwi=>UY5*hxK*Y_aa8C$;ilKl2G!GD9Pb?6>j5&OO&Ow!yV z(yTR@kc%hj$IS2gXtbF*c+rs>s@4}tguPIJc0|eLW z#vDZO?r>h){pR89_>1zXY2dFmUaNce0du`CtF2maNmL5Tk7w?^VmWk7&k9?LVA7hp z3)$UeLLUt1`U9l5mdE|4+dg znR?KWopvshlC0@1`44`a=+IaiQNeD+ymiOd#qLb7BI2!qW@ep7G;9lD}<$A1~u?kFB#5bK@HIDhHY=y5qb$MQY4 z%;ThRI}twkgY3iWh5wq(<+{P3 zSODm#%+#n{N6dUeTHy;(dMCMypzdUb~z8@c7M8Zj2jm+7_X$@nsI$-o#=j>_=`xr$8^K3Dxc9;WPJelb*sH64}|bKC8WL^}3;XF5?E#EV_^avw|DbSJM}bCN0QqU35@^6er8 z@2L0oB30%quPEZvLJb#f7jv0C{N1jwTt(LZGtIe)yS`=dUPg=ih8y5w}`K;a*=*=wYqEg`CeN<3Ho zhoO**tJHpX8;&KB8|3_i$BU)0F}Mz8S90&gv$Q>tB)DhcgKpk{2}g2^1`mb+^!!s+ z;M2Kdka3OG@fwCNRTfIVCr38m4n62AU5GdWm44(z%u6rO7(m^nHCC+v+$03Q0j79n zFado0hsU+6^ z#ot0MIDtVA-NFUv`8Fc{$XiUT!t)G;cvD^E2k?)-yw~38{|t$AE)nD5*&9;r{oU8s z<#Tg9Pu}dRLdGl@8`dFo6L}Ds9w?n~J#S|*ge-&oQ`#bq%YupqJVjWrKCoSSAKY6@ zc_V~{DjmKxm*HGi)fO`6XnInfM6pUr!OwCWLw~rsG85Vz(QfSN$`bzH4|2dPy_3iR zT7KS7eF4BEZ@U&J9dEQL+$R)eW=CI1egF}Ezbe4j!GINr1<3vtL83(H*JXGr@>LfP zxKeO|KeZ0#0TfCE2XF*2F0c{HPT2+R!jVBo+U@hcDU1RF!~z)1JY3#Lzi7J!;?29Q z=yS;ga{Ec+(btr>pY6nU_t&^;pS=?f#|~hW7QS9Ji!R7#mSsM1ugTev0LYmUBsKs?46bRcDoZ3zBi44+?Z$5_ zkgk&HCo6EfbrXxom!8RXH3|UI>Cwtc=eITl9gK^_;PkAYN}DqFZ1Ap~9|;@npA4q0 z_J(atqQE3q9NB1!xG^J^0$kFBNAL^Pv}0Ly^+z)T$xZKHTMiLZM|@i`eFx-@oUj-?K5wat^c zGW-$hvT%BqjoeTjHp)6abTmSwf@A<4b#;aU`n`3_Ray%)1?uWpYlrty>%5dxDSHe6 zItGT8^!0buH$7&si@n3g_a+FiyFH3Fh20B-$|qrGT-e!@hs4M$ONR69VX z*{5Hm{nc+2bOy(jwhOZU@pq!HW)rf1%Kn`rKpn7Lqaop@YW9d2w9r)9Q0tBu zO>Rj^U^SmI)#<)zh|lne1Ia+1tv9DbzQ9c4Cmf%amSODG9-^ZoYC=^H9|ie^FY@l3 zb!sKV`yF9ks1_tx2p9DE89{92j#>&HzF_fz%5#t@od#t`H|2fsZa9q)0~XwR(AL}m zj<^}%$3%9dk$-t#{jT`0mcCdG@fimMEB z95wIUab3_iiICx^?vCB<(M9QZ6Oktr;rKMQ47D&|-O){X_5&&NFO>^e-`y;Q z^td!ee)pY`5Q)}|s1@f+IMX~o2@QA8mJ4SjKC-F*deOPG$FeXaJ zqYb(m0OZ-uS7~a`%^}IP3dnxeCsYaTDU85X ztmbNK3II1F<0`FU`M*I!@_qP$+kbx}Ba43%s0ti2s&3Z5d^y!+?|?d9T;EGp-!cp` zfESIzH`(~1pkvlgzOw1`8vp?D^S}QE*m3O27DIu9Gf3bw;rk^|H}R?;>z|t4x9LvN zf2^dv<>VRzm9<96jRSFsh*EQ^@Z=j`BBgnx)%>&yS+H|&pf~8de z#IOqcD>9iXT_BKTZTuG#2^u#)O4KVe`Zx-!e zfz=O$&-%}5z0J|Kugwv4v+>%b+G1^mQHH3ji?h-sPD~ zi8L%BAc}^r3B%Xu#L_(mtPQ69Ug&PqPXdOVw!oRkL;(hqVppmZKxW@h6S7sWm7*$) zIAERKe{M`z-(cTM@DPMT7&x&XbGr8 zC|66Iyh&t)xN&kuQBI-D?Ba8lBsvB|Xtry8gR}qZKyA(=n#WrV}o|h5P=e zDeuc2zDbSFJ4eNjDCI3-$Na)|Fn_8}E4hcvjL5gXtO? z(hsubll*F|fTKw<=JCtszbwUaCm!)P8*W9%kyslgx+%LwO#T68S!Al)!eMNBdh+Ip zrIYT)n_zDPIqoGQ#Kgua+JaB@<${z*R#sNx((f%V8B@Efs-C7)SC2-Fj&_#oC`@Gq zgY2lCUZbYhwm9DSor|-x=h*9o?+w7vmd-E6DHKL?Abvcie8k)S5nt?bJ=1#M<#wG( zqm20qP){O}xul{;cYzG?85Ug^i7yy&2I}XYh}xpz5cF%i^iVG6w`#8KO4Eds08f8+;; zcv`ju7N`bnbwqm|6@KE4$&v9vBb+mOn=~CcoP|tfgC;ZE8(C|~px!H%YA|yAeNoZ1 z+=wirX#2V1hTaFPZI1*S4KL6Xh2cL+QisR$=aDg|V zXfE8z*27N$6x)NRvnuORrDAI2(;Ld%I$DClatJaBtLI-dlYw1>AJOZyB-lr={yM|c zuMCUF${}CZ1shoSNLOfvtQ41#S7*M+0$%^?V7IlkC5J?P%tn2!#X8F|-dr~aa;M*! zQblrdEM6SfSrNR^4Shn2%P^d4*%_+Rs%h)WYE#Q`(j%9cEqd`?U8uD)v-))Edl&CZ zUy^F=K4X2imZ_{ag=4NaC%J!qDb-O3-R=8o;3D578GOT9mOtEWE&mBMd;j2F#Z}h0;i=>YhzY>+oU~eZUt!d{Na8~>kaG^bx{j*bF}YF z?e{!Yy)6Q3B8*amb*MJ1|6kg@H8MQs`_r?{Y&*q~07r-#4RoKKsJ$5p>%WCHSbw|0 z_cuY{-GJ|krDz=5OI|W^#!P0M(D`$5!@SAax6^%i;dPGZ;>y*zhw&UbDBuFf0n3`1 zOs>jGu>@noWTeaE$m*K_Li(O`6OxNgKVs6g;&W@O_TLM;OLbO2UPH@OA-;fj3UXe^ zk@j6|_#d#AtoDOvP^aPCV;eH_+2ci!!T_0?^KWQ-Faw^dsRdjDgu7#$HQ3*u9XZv3 zy2shf7wVX>7$1n@!yv&hLFf=Zz8)N2t-upt?dXD8`NaA39@Cpg>=WG{kKn_Q`5x}d ztClr~-T&C(gDT^zNbB`)IBd`{?4_2LvwOZQH6_X9HWmJ(lCCbS@#OTs30UyMu)%U8 zV1smN6$7p$So2nByY95Id8QDNcvdeqemfQwBTk1gRzDHs4D{(D%aQiG;6oz%BA!Lsn{h{)K{iN)xFk*k%465yCPNl6MP-fS zf2D**I=XJ0)SsWfTM7vHY69+x2{FYT;{eLwXozR)*+y%yduyfnfihaQ)Zfd|pZjrDDiu&w<;3d4mW|2unTDaxcZ|0)%0%6oDhC z2giAD_23rJ_8Y`RW3psMFii{l2#_Y9{Hj$P^CydFfJpeLW{IypsoAy^Dz!LnpG-@e zBp7-)8yU6RmUMX$Ylf3UgkAR6``vf%EW`OO&UpAOwJpqG9)FULe!hG~xqtOG{so^x zR17nfgye8S>zZdSGrP@)x|0;IlKFsRQ{0-3*PELmtFv;6;)$?J;iBc4upjv^sOfKI z-_ZZb2sLLI7y)?er}`lMdUtt(Q{L`2THHGz!VC1odM;pu%vA@d4$*aL_r+ZG27`?3 zS#&*qPE2_{Phgg=+4T7o?*SB9)ov9O-EBLsPPtp-_oubxIu);U#_p|cZON~`OL`11 zPoY*^Jyih=mZ2@+t62V7Gq9zfcFInQes&9?s7UWV3MCAJ`DNu~4CkbFkvEpxn znR~Y{rB6ON9aD{pZ}PQTh40yoC@A3%$2h zDi=IEh3Gqe#CbU8i&wY2H@6ywBA9e)p3nKP617`WEh_2J)r4K{cjV{i7cIM1gxA+c z^<48%0TFsct!B^Dvs={KtQG;b9^@@w`zBtwG1}+*r+tPR!841q|pozs948@qiF5~agq4h0RZc0^+Zd{ znirn* zjr5NS>4PMg0=0MDJ|`xGUgHqc;N?W|DxRwC_V?}N4v-w0*6l=AyoR?0GK_le+>Y`y z`3ld?X9f(7tjHtOi6JWY0A`{0?nK2)$@#oigu9hL{zlcxQ;n?$(?u$2=43iM{d->f zbC&WrWDG~3b_-fHL&v}JA&^jUq$9e`|I6jY6QvPy!V?>raIC$f&>FO6IpKI&qIn_T9@EzY2$$#{+Gs)8?aS zIK54u3bow^w?T#NcjUnPE3}VRTToDF*Nd~@8S&2U370SZz#Gf>--v+^S#ph{cX21K zp`pE=HFsnbFA%Y@oq9;56Tz-De`YnGJ%tM3ok-hS*|~(|xdlhd0a%N{4>ot${Ev)q zwom%i)u4-c=oU9Y8NT}Azk))(Z|xZ9)O^xIC$O_UxT;mI59^a$4zI0nU?x{r`XXD# zZBcMZl&okcQFPafZOvDV5?|*VWT1;e4fI@dzw0@zzAnDMa!1o z5-=4lQvbf)*%dULqzq5Z7^TDqp}2ml04IlAjGyW)?9MC=c5x*U1>6o0QZy}#tHU8WXE$Zs1})8kFR2Z_fE4@#~2pAf4k;;+RtJ)C?t`SGWm z8>AHIr!D5OVOvvga9*vRj?c^%eos~qVn$XdZXDeVI+5)NE``&NFVr8Is$9H@)hvyQ7A>?&1cCTP=WJxGqa^x(l*!PHaxv?xK5KSjh2uj* zL+aPFcl*?}v#}3FUDb&3#W0S#6eXbC{`9{W)I|=u*y`$E?lw#9bVI9OS^w#h0qpmo zJ=)cgS)l6R$AsZ8j4$B23fc(`N<`CU9IT2Vjw_F!tCP2Y*rR6L!9teN{=>$<^Y&fR zl}E}ajDW9&@K~{nOEHnU;mMA*C=}YfpR;KTVDo>a**OgyZIHwJ2HvM+56iYkqdh0F zO59o6H-X$d60?8D2@lPu?QDdzJMuP-K-!Wn;ZpsjwG~CTMlQ;Z_e1@#O&($=`&ETS zmR^<`8&fyF)3CcDMzfg6hMbk={dku60$Nc4R14;}xgzI2qU=SAdmgGhvfpg?kpc7j z=eTbWaI-`9M>{{@(#EC*1v(;~gx) z|EbAxp5F#6u=6H!DZm0Jmz|O*J73h5KHb-JTubfA+h%zZzpJo)sV>jOSR zeRqZ=JsNxaI+`EI04*ufrASCzR2;vlGPi#?>?t?t0gr=Hn(j~vRUucNqnxalh_a%| zsJe{IpUQX=%!+!(iktA$^Us^n3reJIBzO{RI4xw9;?sOlF07I}2k_dW$pK+NG$Plqaz&}gaAVW{r^n4vYFzp$`?D6^ z4PYtCj7Zw#8h$~jt3!%=-=t=0q~kZVmB|N@ql`Yn7ZmU~O}!c+o0eHNei^p_*byJ)3o{xfgq5cPUh!BBtNWR z=AXFF*4J{#$eh!NXVC*Xq!9tGB$RxLbrb_`6a9B;1zu3+P$b00%7dE;(7a%Txoc`} zRj9sB4Ml<;omD66`g+x|hJ$IR0m&kz@`+=sf%1u{@`)8TH2bMc_Mijfx(A1|y{{za zxft)r8`$OJp%0Rrfh|{N#S~4c)XuS6Xk~v&A!B}mxxE;n9_YP``P)$@u3O`bUc))C zON*gxyL#+JVXP9cpXfj}kMh!Kb zTR>Fy*AR>x8#8t|v^}f4YXSW2ZRYM9<-QEPy?NAq$l%n3zHp{ob)b!=<8Go3={Md6 zeIycIP#t2`dj4B<2s@&oAK7imw182ta{v^G7Yp;rfvA{0kqozXh%&ucHlIzJ-OB|M;sugve&|nSCo%Oycw50kz`$EV;9x7)pzuvXx{lx9lAp*g`H2 zO*%}i@kWjH)$;LfJmt)FlAycXX>c6%-LYmq?5cbp0DXz^^9YCQ*8jFstlXtChfyA6 zM3jhg_*x%A4=e~UGr5+U)$N2S=Z~=k1O#ck7dBfg1+`Ox5km{nq5u$b7xz3 z4X+0aQWC4Aw1rJ{xr{hU6j#`O0c|Y&&YUa(W<~5fG2j7e1yuqB=Q$OSbpKi3`4cA7 zl&v8Jdg#8_yXAio^xd6}J4Aroe*Y}9YvZ*u^BO#TV|GmTNv;kr=3)HuS);mH9tg!I zU(DU~Uzx}qj&hR>WSt7Uom(ayn%^C~K@)-U|Z_ox{kMf~9? z9nZ+PzhGGzhR2knlX{)+r^nUsCjE6w>P4&>cX2VBl=s>TOQy%gvxoAFxM>u=VHT%S zedLRiN{<`pP3mUTAIV$~8nqYG2HVuQb_@1MrfYWPX!6?G$=Yv$AByX>cTW>@une*f zMf>hp_KT*+-Jg~&>lhf-LuY^CO{!RLIi7b(H7j3iIIk^R^_I#0ceH)VDOEe@lGN)z zVlURpExl^5^QVMao)!Gu+p0sabEl-$6#2D}JCh2Vz&1)BqNP}Lv3UAV|qZnh7d;_Yf zb{h@i&wYL^qZs~IN1zj(2$Hcx(BWAW`1q3Vt$qb1>-55IFJGp?))6n^nh83eBaQDy zL_>;4c^(W}MTBREjA~~}C7Sfjl@#%}{Y1k{t(pR(_+PaGEYIF<5_oG&kYf_2D+JM6 zK&Nk?GoTpTJpM-WwY33XzbZdSG`h!Zg~o5lGCv{j&^@Ts7HzCT-*JGBOHN^Y*brc5K(j6)rGN1&>H_mB+T)=JF*eLY&xM{803 zND9IG7{X%}0PDyXgY_(N%%e938Bcq88anmQ#3Ka=>A(j!r^EUjD1wSM7U>DEZI^B&RzHG^V2FheeP(Tp#C|mtz7*F&j!$k81F~@Kc{^rM! z4+Vq!%9!@+uDRL9)MbCNeJrrD9dp^}@+4yR{5Ip(a=G|Oz&&O{H;ZOaSzFw8o7hn?q?-sYqqys+fcuj?O zlWW=SAipaE;Qk(f*XA{#xohNqUnTti8ePJDoc#n_S^G}GbCiK6s@f0Bl&vHF2kPg8 Aq5uE@ diff --git a/images/favicon.png b/images/favicon.png deleted file mode 100644 index 26f009f8791fff1ac019756b1e069ce23e3babe2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58136 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 z 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 diff --git a/images/picture.jpg b/images/picture.jpg deleted file mode 100644 index 2336b37427525b627d32eac3292adaaa9f3a477d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12929 zcmbVy1yo#3)8-w)ZE$xV9D;}7?(S~EVX!~~fdmNdZoxee+#x}NB}mW&2^us6Pk;bB zyzjT~_wAnj|J}1S=iK{Db#-_3Q`K|3X6A0;ZWVy3C@3ocATR*fAz#4V0e~;(YwHpK zfB+}}05nL|I<}FrtgNM$j;4aLnmhmk0RXm=nv=T+7zO}t?mh?|MHxCHV-q^GaR3Zp z0H^>T09f04d#dXy=pn}dl;vgVypcxt_}_9dhnxc`(_BhgbaemL|34voTTg@!0D!cR z)&h3+-nK{_hQzM^KA!jbBP1rWak}A@Oe{CUUd4_67hb_PyT6-u5vP z^CB@eLQh8)i5~(0I=16~V4MHIKK4(Legc53hi3r7$?>rd9h)sX9iOPE2%VC>zpK5E z50{p;t&26nj!xFY&C}XF02!^n)_mU!Ah_q24oR{QpQw-!7e6&XRNIw2s_wT;{)_D{GfXF$Lo5X+XY_b5LH5>rQzW!UsQ~&^YVF1uF@gM6U zxzCr!K0cmeJUssX{@hOXw%qrG{v-cagMTdlYw#cQao^AP4|jBO_72v*u0C}4q}qD8 zdiWyfygjXL?diDw_ay%R?)V>W{f8f%I`$6s2zz(rR0hZ_b8>e?hTGlF$;ZjVozBVq zzl!kxXSe_G;U4~-*GNEEatjbyas#jlA^`H^BLF4D0w8Aj$QIB)aZ|%E0Pc65A?^0x zd5^@%_P?(G%LSZ(d<*t=a-_Rg%j)RS+4>^iZnzyX2LIdG|2tni^S`agc1H=y!0X+iAgVaDeAY+gf$PwfY z@&!Euy#&R8l0n&^LQo~B9@Gwc4;leYfxdv&K)aw5&=nX0#s(9CslhB@9S@0@&AAAl0AXpF*2t9-gA_9?xXhKXN4iE$+ z7!nOhhZI3-Asvt*$TVaXasau6qCyFwbWkp+I8+I$54DAQL4%>O&}?W0v;{fp5h&>>Whl)kgDA5oTPPQ(sHh~Utf<1MN~p%D&ZtjO zV^Q-^>rmgJPN8m~o};0mk)v^-NuX(>S)=)&MWAJ&)u8pFeMZ|t`;Cr;PK(Zuu7GZW z?vDNfJsrIYy$Ag>`ZoGC1`LB4LkvR`!ww?=BLSlXqXT0CV+-RN6CaZmQvy>D(-|`q zGZV8Ga}aY0^ArmUivdd%OB>4xD+DVO>n+wW)*99&HUTyqTNc|4+ZQ_?yBzx+_806^ z92^`L94Ql3SP0|^>+)cbn0wG}` zQ6_OENg!z;nIpL(r6!dowI_`tttI_T`iqQ`Op45&ESjv2Y?kbboQ_J z0!jg=(5CRG$fp>jIG`k=6sNSMjHYa${7MC;f>Y^GJ*6t9`bc$7O+&3n?MaQiwwHE~j+joG&Xq2cZh-EHo{C6NOWh z)19-3bDj&EOPb4%tD0+#n}l19`vrF^_aP4xj|oo_&k)ZouOP20Zwc=r9|4~V-wVDD zz7u{pzb$_b|BL{RfP%ntfi{8T2OJOVALKt+5F`{-7knkyCwLt9TcvxUC!?33x2Vsi@2lTufM;N4P-*bXP|h&faMg&%D9C8cn8Mh}xXlF3#K5G? zvJ1rn_QbC zTUpx-+kHDJyHvYfdkOnw`)vmahh&ExM+wIi$KA)0kJBF?ILSI?I~_YKIlp%P<)Z0Q z?sDg9=vwE7?q=oI?oQzD;y&O(XzU&C24hsp}2v-cRj=+sTM9jYufAu;N z8tD`{9wiW!6?GeJ7d;xo8$JWGwv?lA$~kTC?P))HPJnBE=e+}A{jq9 zFnJ?IJ*6d;E;Ty!EX^`)B>h49>kP~c-;C8vwam6GrmV!QKiQA7XLDq7>T;=aqjG=c z+2wuCm&&hwP5nCN^;LmW!9t;8VM`H9QF<|Iv0w4`5`&VVQjyZiGK#X8vYT@E^3@8R zih)Yu%E~ILs)TBAwQu!qjakj)8@V@awOqA@btH8$Z-KYIZ};l0>gO6%8~PeW8f%-F zn{t~8o17I>bAgJGnc{yXd=ex{13JdN6y!dhU7yd(Yo_ zzB_pD_7m|XiQ%phv61#skuuMZ-A;Qz=yWIJs7DfRQ?kL(V z`O1ac#r3b~-{ik5E=4Yft_-iXul@g^{mHyxzv;MDyAZhlhMZ5EBp(6X7FY6htH>L=-F(6jT%xEWC^~NMYpV z;AUlI<>n9+%AJ_;2VgSJSAP7F_ZUCr8mO_6C($jwl2n>Ou zp#AS!0APtB|#08$tpkdG{m#Blub%dO*qw zM#szN8RB*K6~IQ$3C4%uBQ0+JvHCv&)oi_jf9qj-#3<5Q$cvKG{XHU4kLa&PDEK{6 z%LZUr-2*_682s*EouEhq@OvpBTm^szTp3U0sYq+xpA`WBi~V0F$XhDN3UElpVgqZl z0cf#)TRPNas-JDB1yIjNY2pI1dRlW37v3{-$kN~+!H~iNkY_?Rqyn@--A)jq0xQx| z0qEbHsLq?Al?SWl1?CFpOii#l#XG8<Dk}#TX{?I^zBA6Q3ymfZ6D_05wzxX@iNKQ8I$Dt0q?54U{+kL<7B5_|& zf>BcWdIIJ-13e@h8>x9I!kSWn6{f)R&7TuNoQ_fec=Wy(KqHvf4!lJIv6F_Y+(7T0 z)2o1`W8-N6ptpw=tJ!MJ2@Z8i1cW0elhQR--J9p`Y9R;#kO95#tb~k5l(iM66oB%h zKcM^L>2ADv{d7KR0fw||O}nl7N>*1OtC`FfBKa4issKu;^?dK^sR`>m^baX!Ps+6n;Z8ltR_6_L-+Eo2-}AN)@qSR5%UpPlc2ODI?KPn#AsC;=PG zBw4L+BD#%MgxSB^qN#fsFPa5@KN-y9B?6#DfR+?U3f*GqsiS$}m=8EP1nD0T@bLCE z52-u#S-|;3X=`n%J7Rx6H#<)N#3rwY(lD0f(AYJG5}*4yJOtec3(x`~Ybr>&#P=&S z?$p2I38m57A3fbK@tW7*Xyu$2ugJ^g>$*DKKJ)qH>}=m|q#w$a7a+g%L5$VHTr@lc zNTmb*s_p>)-Tq##nfA|r9fLs!cR$TlWwM~noR<~eg z_Erx&x0`o{x~*Z6SI3TnPi4NzpvyDFe9!N|rK|c@i)V8l{7zaJRz?7FtAV7TDA0SJ zUvB2RNa)LKgGh+`?*qx95eKDPZzTW+p_1yZMHcU%kwOjE}JWt2l9;er$w^e6%G(B zbKdhTBw8S89J@d<&mUt&10DCDKcKboT;J`TGS|w0Q5L^E7M=6mI3BYtL-C|q>zbY1 zj#5Xnoew+Xr-TWX5;+|W8|H62KX`H%x%9p^op=`THOp(xy)|#!B0gUuPheUiz<--q z3%SX9{)le`M#WUaLy$9k-`Lw2GW#8PsoZZ7PwbV$vcFmVhb5v#PD_JwOOV>_azFWH+7?oN8 z%2`0i_g}9h7O{{Vf!24an#%;3#;cCH#gx~FG{iox>}x7;&YMm+IV+EqiO!Y$AgvX4 z9Z)u!?La-2+l`^RQbJ6qWp|xf1V?6lV^}}`>b1RhTE}HeDyd2(em;=L>bmX|L6HW$ z4HQG}=VkKQ`$)V_2pBTUz0O)_aY1*_-L~)=|71whRg=A4qrc4%STZwj^4&U*Vz6m{ zqJ*!iGc~i)-4GFQ@ySJ^J*LUK&CtxTBx~-HyUkLhLn^rjN5w?fS`1$WoMakT?%|i^iL&GI zvk7y>P`c5eft?a+Il>cwNw|uM%)hvCN$(-K(CEzt;bL%G{PDg&JR@i zofe^LkF!?3{>sM~}#DRHGEgjyh6 zq6BN_#Vs*o=;pu-nTrurU#PlBB6szl_7J-Ipl)-J0g2Q!%+sf0W%79=%2plj_ zl`$^0k0J=J6Y^xYOV4`V2l?-MQ54(pe{74ll6X^Tem>V>XhO|XDu2==PUe(J&-hkz zCGv-222Xv&&HSQl;mgvArNyR;Z_=FOcGAgcXoaLZJkKfg@uY<^09by=U|?uytayUv z)DHa--6=M;q(X47c?22#%Yvh4XUbPU{)z|WU-3Ytjcj)?YZTRxG5RBsH9W2}P>+#Y zI+k0&SenrHP0AS(oa!zCo-c*POoO*T7(MSiK39f44sTO}2oFwP`5op?ew&frDR@m4HkYMS9a zaRKfPN9Ac*x#pR*G&5+BrNm%^TY z)WjXN7066!A9}QJg25SWJ)Xkx_21lq{^st0?%T%C+Fv|nCwIW=^|xT;4a+mobh6Pp z^bGBtkOcQ_?bfd(c&Wcxo1h^FCwXY@oKXg1pdB&LtMJr+`n1rzyi$<#L+uR&AL35? z{O!2ixC2SbH88w@}Em)1&Nxa{v+iG=f+RGEIS2P$>~(Ck^3%AC z=Wod_;l>#c$sLS$Frbbw5njQ3g`g1WH0AG-WP%M+Z(<)quUSXkNya zUbMKfKC#i+Ziv()^_&N{&rqx-hPQ0qB3qzkQN=)fiTVw(%q+kCa@NSL$M*^~@w3Hd z1PnwQsqnVQ&J_CiN6}BJM%lPByzlGer5E!ycJygKXJ+2$JF`i{%08A*d+^SJhF5r{ zP-2`JQ$16I^iI0QdA0N0s<)O zWPaws`;DIFENA@B-C$9IT3#k%8!|)fE=Y8X%w*g&8PLS~*~YwEz#ZpY%y$6?KM}B4 zFwP=$7Kqgc1dKVW`0Cg`dFD?o1X6SQTV#3cNt7#oTvyZvRTQc@T+Q~rp>s_jyhNmr zE@s7HHNxokp1Mf++tBeZ2kJ?lZJhHt zHR#Wpl}tmp0H%eFx6l`K)GVX(n=7-YnO1v(^+#D|h(USF#OPx)0xB}Cg=u`UQ!Z}r zf&)i36XWPvoFK=Z8@!*?XOGYdhvIZ;>3_ZTDB+0QZA3K+@ES@C2SnBtA0JW*;D#AJ zP}CN^#w(S`{0gQgk-!S!+uWGA{F!kM=nsFlnpJc2D!?)*sIn? zinw{;iJvpK@NtBSh=C!Oz+tN%0Cypa7Dfz`FAf;>%f4TjrS&tLkJhnmUr)HI# zsybWPCNCHPKj-_-Yd?g=m2QyMGb8l}lRvUY0)*(xq_R+uxT(j_Mq$AY-WI0Fx7EL< z?jFbw*qfCpTxX?Zdtx_=i83s5^9SNc7h7XvXK$P4DkPLkkLvNTe^)Wkt^l2Z+GAU0 zt^Nf#XI-W!Jp7kys%kyT@4`nj^if})HH7O(jC&o^6D9Lie!8$Xd!isX9EZxnm)4d; zxQt>!{gT6&7k$=O)gKJF@W2&)88#mZuEwhn3j}@kex1Dc9w&)z${EjPmDk zsZzl#+=}oD`D^U;T$x7VzCr~W`g(D~sHB%6ZKozYR3Youm~ZpNw5d7X1oBN$6f{nn zJ3|qu47dtFRRu+hNQ2hd`Fm2ql ze|bf1b(_v7S&aA{*~FiyVHAd9oRFOc$A@p}RmeMmp;FB1t24iNZE8T6t~$vB>v|+_ z&>0x20R{@kr8|KC#b^n?4ZzPA`A*}R${p~9`UO~t)`rc%H7s<1#b_avEB>YRMS%r9 zfQhZ;8maZbOqw|cjZW)WUrl6c{GlTug|>^C|C_cK6sc^eUc57>sPO`lTF&fO$D0Em zOOXF2$(4|I)YfMre3NA%t{=;nlYj@kgRP;!#g1O!GUE=0~a&5X;_C_gX#M) z#C}+sjh<$e4W<1<0idQaxFow>@k5hczY7(IKNi-^)2I+3p|$xGSRqbsK{8RYSEKx`*~f|4Y7`c>$7Gd#8+oP#m0W^)WWzZjkolzt(v%aEi$RM=`T{nG~yM!BoK9s^=N~5mjn@ zBu+`>k`24$I-c`gs+}EO{MR2)NbC>PY$B(`7sm3&pfpER9j{lorG(6!YVs2^I@oq; zgCF1o<0@$mdZQq-c;r7P?3vV*hr<=z>D5gtD>Jx4)r$Gv?pPV7$!%dPT~s*a^ik!G z{@{z?CD5P~tv=3S4y9~F}(A_snRhku%{l^Izq^vfQG;A zQ|%$X<%l@AGpzrhZqa%y!09sVvM0sQ&+$0|i=UFJHi)xcS;x8G7UN=*?z!j_Piv`5 zX$ZZ(#}32uT?F49pcIoq_^xVtKinEp2-C0jC{M8S@S~yJAfcXAk1*F!bTH+GEX1)tys48dhe`!ww@+@uD ziYBjslWeE~aK4Uc{SSpFk;Ws#KZa;f;bfey?@$}5-z6kP!PT%C7BJ^vQ-;=jn>wYS zTfpevZy0H+ufH9iwLBz{ri%XqExITJlZ3+9EHBh3#?_c81f8cIUWJY|(1x1B7;Tp8 z$f)YT3>;u@5+#12n6lj*kWZOHZ(6saXRyDBEr>7;lWtP1z)i>Q>D!WRC8<}Dsp@9o zj4meUq8gHVOK)IBbd1H5X;noVWhdv9a(NsTv!~Cxl9L0q#YwELW%~jOkF+1@^JaoL z9$4uke^R%^&&svAs9vPh3j0!OH4-oMVc2GILuPYb`ytCihcUMJeaw37u0ov(ZM9Wt z0|o?)n*`-Ed!!rO{xbt$Je51npBB_~h+P|)IS zs!38=cwdeoivi)xTlUi@ulI+JJ+h7-@f^k7)*s&iLMPu?f3G3q9VIYu*_wLtNV4(7 zGF_8_X=p3>$*uZ{2U#%Rt?J3t-&HdhRT4OzDN-#`N9|xge$gjgJ6UWz!=Ce45q%KT zi)M!>s5$zFvzu)3FAtKk-4;Q~70bWNyZer3QZ`#ts;h-`^skmYvu2OjSIIzU6)eyH zvH*dQ7I#1)O(sI||SKqb>IyuZE<`aLtXi1pS z-ao#H)PL&BgUJckRkzctEgN-qGgsEDSnl|9qMW4rF=|hwhW`PD=8l)=*OPD-4v`k1lp{PH};u-|-Gmy8~E%zv=knRZzXBIZ7Cl*h`D0>OA4m zeyAUFlU4PN=ng=Xf+oS*^ukpJeyJ7{N+8}(5v%w zgmCoDB7v)dFk#kG__xu?FMF+*GWlafhr2(=&R7kYQd{dqdqr*{El_;s+v|o|b*C9y2z;~YT)=Vr#XwUqzTtoUb zn`B=kN7Yb2?SUmR;J>>pxW*~tC}Zd_#QM9iv2v8HORVmdu2OkOUB6gvVSOq8BRDJK z`Ip!Ak2$^m7}}UP4;xr8{ytjRm-v&Y6S384?dVl=Gr_?pfqtNEU9A~qRIXnhvC$g( z>YV*(awCm`P4=L2dO$z$x09Y@NBBdWU<^NrriHFEjzzqIfvYEm3CeQL;U?9;NjGJy z*klm;lj)U32l-zJO@2qoWNU_LDiO0L4Z2ur+bS!z%Zhn?3*P2ApOp|y_8zAhEpHVK z(#qF2En*3?F{e#tW;c0n`amI{wW#zd<*vtz?h~W2gtmGUSBGVT7fw+QanItp=4EOY zyPVt>w-t{jW=gwsqATlck5rke2{dvDW9CreeFDk0DpkrfCtbvbW{^BSX;?{Uk&wHk zdBm=E(@Fc{Ny}n~AK}o72QJOlOAQeULqNDONwh*LV!k#DFQ3Arl}fFFM$e<#uNOgo(0B@R{?vpWpCGhUDOv;G9_OL!yQ4)H>k(MS%xu_syRV6+8^*xr3TNGKxiu&TbZJaH2q)!aZz6+DJ zHT$W}nhTRb7R}ds_Tu(Imd(vl4#JxOd%Y1u_!1v`*_Kz?7Qft7U82I*lvUP0&MeDJ z7rA--KDuvD+_NzZgow0K566WA8(P`z4Sa1?8Y(^@_h=E(rL^wJDJ!vrTy~tQhPkG% zki7Gu!Z#hlj7goJg&4C*f=qR856!rg{IC5KpM8IsL8jEPVDyQ$;`5XYA-(f1IJ==L ze$W-Zt0Tz9wH&Xdub)vTtxhtqU#Q4eI40H&`&}eZ?Wa8B6^CfmT-)a&n=$~SNyRfgoR+Lpr0UIJS=d-g zyuO7zTd*>1GDp%6gyMWdck0i=LP6!}mZqPgtbB#~#sv1<6$%%yoWh8FDp3KMUo#F`V&xK77ib)h^qp)Erj+R&i;M`<*O%`pCRo1^1gY~lAC~2NtV^nW=aVM*pIa}MU zZiLjw5KW)hjvkAi$ex0+kh0;j$G2&2EkuI`*_H~$Qra0S zE8g&i(NsL9lXvR89nS^4wV>2MrOvx8U&xT^Mj<&{%WaWDI`s>j%JEb3x2-zam@@8K z`FM`6%^XVA6nZv;%nhtU>Bg>zn~@Q%w4jmX=Q3rYTn6QdubE!i@VWc4<(`Z52g_{5 z871ol@)HsST;Ygax=S=s&S=6j!Zg_#oR$YWV#a#Xo*zoQe#usjFx)d#*Gg%X(KqRe z>Q)XD;ZZ}hgr{v@%X%0He<(97JWr?bq#ysdQPO=R* zO4o?Jn5O>4NS0^H5+L-nV)(07ahFocSu$bX$jFCJ1i8%JA7&9xIF3U zjfc+J_6G8cJx+WScqp29&i4gLFn`PxO({FsZrSh^u?q8P%j*=$+1tj$qhC>51&DW2 zy>8|>XDfuwPx_=Eyc*lJK4jTrn#(qes54$DeGqDmKjU@y^g?G5ws*!>vu8peQu=$z z-KuV*ZADP7O-?vSzFuROwcO?>`#JrkQJUrCHZgO_*B#kv7DN5|DUx$q5*gvgl^B-V zcFRJJ%)2C{tor7oRpv>>HThG_7R5E)gVB11Jl`b{j)vEmE|{fk>6>cKhQXx5#zdnRH@|!4Zg{4lNo7yQ_j1U7^XU=T6;PenjbZJiX<|{e5q_{d>+=y zlE8OK4y&zoySJKG)pZMhRPS*LE$E9HGgdDcm4BDzNqZ^zHup1z$_1g<;L=8164?|-V@iJHcG_Inmv_zX*Z7Yq$FE7W%acZ~q{${z ztJ`s!NnI~0Im$2yQ)twVzkIxSvz$cQ!bt z+@Kb`FeXlSspuA(-$B(dN;ny7cp}rWblL^0mB8T82{+~tk(dqS=PwkQUoG6jk5WeVy8-y=8}tab3%?-5Uw$gF{Pn9M(3CTtGyF_H>Zdr>mGZR z3DuAGPwnd31hoeNMzOCNWYo2n()8f^yOrwhwfZG3%(F#^;ILAWPYHfaFD7I3oe-R9 zrXnc{;3tKd$#3(Ud3DS0rd4FCh2PquaPiuGfl#|^7_31dX`;&;ZF99%#1LKBlY7O=N z8M7c`@g1fE)n4gOM7oHC>6DJwdo z&3|!9d=R+Dv1nO;qg1!&EU7y)b`=y;9~9xVXJ>msy4W}qY#BWGT|E0HLE2*D8tbRm zk|FVJ|H*BEVNdzVbC#Y6i*&wgBg^^8TQ<y7V!_4iS0T*^7<4w!bBlf@%b=zIEJv F`5%APW^Dif diff --git a/includes/header.inc.php b/includes/header.inc.php index c7787f9..a6b546d 100644 --- a/includes/header.inc.php +++ b/includes/header.inc.php @@ -16,4 +16,4 @@ reports
- + \ No newline at end of file