diff --git a/src/main/scala/uk/org/floop/msc/comet/WeatherActor.scala b/src/main/scala/uk/org/floop/msc/comet/WeatherActor.scala
index e97c5b1..779dfb9 100644
--- a/src/main/scala/uk/org/floop/msc/comet/WeatherActor.scala
+++ b/src/main/scala/uk/org/floop/msc/comet/WeatherActor.scala
@@ -10,19 +10,64 @@
class WeatherActor(info: CometActorInitInfo) extends CometActor(info) {
def defaultPrefix = "weather"
+ def COMPASS_ROSE = List("N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE",
+ "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW")
var currentWeather: List[Pair[String, Any]] = Nil
val currentWeatherMap = new HashMap[String, Any]()
+ def direction(d: Option[Any]) = d match {
+ case Some(angle: Short) => COMPASS_ROSE((angle / 22.5 + 0.5).toInt % 16)
+ case None => "unknown"
+ }
+
+ def knots(s: Option[Any]): String = s match {
+ case Some(mph: Short) =>
+ val k = (mph / 1.15077945 + 0.5).toInt
+ if (k == 1) {
+ "1 knot"
+ } else {
+ k + " knots"
+ }
+ case None => "unknown"
+ }
+
+ def temp(t: Option[Any]): String = t match {
+ case Some(f: Float) =>
+ val c = (f - 32) * 5 / 9;
+ c.toDouble.formatted("%.1f")
+ case None => "unknown"
+ }
+
+ def pressure(p: Option[Any]): String = p match {
+ case Some(inchesMercury: Float) =>
+ val millibar = (inchesMercury * 33.86389).toInt
+ millibar + " mb"
+ case None => "unknown"
+ }
+
+ def humidity(h: Option[Any]): String = h match {
+ case Some(p: Short) => p + "%"
+ case None => "unknown"
+ }
+
+ def rain(r: Option[Any]): String = r match {
+ case Some(inHr: Float) => (inHr * 25.4).toInt + " mm/hr"
+ case None => "unknown"
+ }
+
def render: RenderOut = {
new RenderOut(bind("view" ->
- {currentWeather.map(pair =>
- {pair._1} | {pair._2} |
- )}
+ Wind Direction: | {direction(currentWeatherMap.get("windDir"))} |
+ Wind Speed: | {knots(currentWeatherMap.get("windSpeed"))} |
+ Temperature: | {temp(currentWeatherMap.get("outTemp"))} °C |
+ Air Pressure: | {pressure(currentWeatherMap.get("barometer"))} |
+ Relative Humidity: | {humidity(currentWeatherMap.get("outHumidity"))} |
+ Rain Rate: | {rain(currentWeatherMap.get("rainRate"))} |
),
currentWeatherMap.get("windDir") match {
- case Some(angle) => Run("drawCompass(" + angle + ")")
+ case Some(angle) => Run("drawWind(" + angle + ")")
case None => Noop
}
)
diff --git a/src/main/scala/uk/org/floop/msc/rrd/DataStore.scala b/src/main/scala/uk/org/floop/msc/rrd/DataStore.scala
index 279fa90..e574f5a 100644
--- a/src/main/scala/uk/org/floop/msc/rrd/DataStore.scala
+++ b/src/main/scala/uk/org/floop/msc/rrd/DataStore.scala
@@ -114,6 +114,7 @@
}
})
sample.update()
+ //val fetchRequest = rrdb.createFetchRequest(ConsolFun.AVERAGE, )
} catch {
case ex: IOException => println("StorePacket, IOException: " + ex.toString)
case ex: IllegalArgumentException => println("StorePacket, IllegalArgumentException: " + ex.toString)
diff --git a/src/main/webapp/charts.js b/src/main/webapp/charts.js
index 8b5edea..335ee72 100644
--- a/src/main/webapp/charts.js
+++ b/src/main/webapp/charts.js
@@ -1,113 +1,27 @@
-var cCanvas, cCtx, ressie_angle = 0;
-var CIRCLE_RADIUS = 0.75;
-var REAR_ARROW_WIDTH = 0.18;
-var FRONT_ARROW_WIDTH = 0.15;
-var BEARING_ARROW_WIDTH = 0.08;
-var BEARING_ARROW_LENGTH = 0.65;
+var CIRCLE_RADIUS = 0.75, REAR_ARROW_WIDTH = 0.18,
+ FRONT_ARROW_WIDTH = 0.15, BEARING_ARROW_WIDTH = 0.08,
+ BEARING_ARROW_LENGTH = 0.65, LETTER_SIZE = 0.1,
+ LETTER_RADIUS = 0.88, global_angle = 200,
+ WIND_STEPS = 20, WIND_TIME = 1,
+ wind_start = 0, wind_end = 0, wind_step = 0, wind_timer = null,
+ last_angle = null, cache_ctx = null, cache_canvas = null, minWidthHeight = 1;
-function drawCompass(angle) {
- cCanvas = document.getElementById("compass");
- if (!cCanvas) {
- return;
+function getContext() {
+ if (cache_ctx) {
+ return cache_ctx;
}
- cCtx = cCanvas.getContext("2d");
- if (!cCtx) {
- return;
- }
- cCtx.clearRect(0, 0, cCanvas.width, cCanvas.height);
- var minWidthHeight = Math.min(cCanvas.width, cCanvas.height);
- var FRONT_45 = minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4) * FRONT_ARROW_WIDTH;
- cCtx.save();
- cCtx.translate(cCanvas.width / 2, cCanvas.height / 2);
- cCtx.strokeStyle = "rgb(136, 136, 136)";
- cCtx.lineWidth = 0.75;
- for (var i = 0; i < 2; i++) {
- cCtx.beginPath();
- cCtx.arc(0, 0, minWidthHeight / 2 * CIRCLE_RADIUS, 0, Math.PI * 2, true);
- cCtx.closePath();
- if (i == 0) {
- cCtx.fillStyle = "rgba(255,255,255,0.5)";
- cCtx.fill();
- } else {
- cCtx.stroke();
+ if (!cache_canvas) {
+ cache_canvas = document.getElementById("compass");
+ if (typeof G_vmlCanvasManager != "undefined") {
+ cache_canvas = G_vmlCanvasManager.initElement(cache_canvas);
}
+ minWidthHeight = Math.min(cache_canvas.width, cache_canvas.height);
}
- for (var i = 0; i < 2; i++) {
- cCtx.beginPath();
- cCtx.moveTo(0, -minWidthHeight / 2 * REAR_ARROW_WIDTH);
- cCtx.lineTo(minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4),
- -minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4));
- cCtx.lineTo(minWidthHeight / 2 * REAR_ARROW_WIDTH, 0);
- cCtx.lineTo(minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4),
- minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4));
- cCtx.lineTo(0, minWidthHeight / 2 * REAR_ARROW_WIDTH);
- cCtx.lineTo(-minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4),
- minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4));
- cCtx.lineTo(-minWidthHeight / 2 * REAR_ARROW_WIDTH, 0);
- cCtx.lineTo(-minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4),
- -minWidthHeight / 2 * CIRCLE_RADIUS * Math.sin(Math.PI / 4));
- cCtx.lineTo(0, -minWidthHeight / 2 * REAR_ARROW_WIDTH);
- cCtx.closePath();
- if (i == 0) {
- cCtx.fillStyle = "rgb(0, 0, 255)";
- cCtx.fill();
- } else {
- cCtx.stroke();
- }
+ if (cache_canvas) {
+ cache_ctx = cache_canvas.getContext("2d");
}
- for (var i = 0; i < 2; i++) {
- cCtx.save();
- for(var j=0; j<4; j++) {
- cCtx.beginPath();
- cCtx.moveTo(0, 0);
- cCtx.lineTo(FRONT_45, -FRONT_45);
- cCtx.lineTo(0, -minWidthHeight / 2);
- cCtx.lineTo(0, 0);
- cCtx.closePath();
- if (i == 0) {
- cCtx.fillStyle = "rgb(255,0,0)";
- cCtx.fill();
- } else {
- cCtx.stroke();
- }
- cCtx.beginPath();
- cCtx.moveTo(0, 0);
- cCtx.lineTo(-FRONT_45, -FRONT_45);
- cCtx.lineTo(0, -minWidthHeight / 2);
- cCtx.lineTo(0, 0);
- cCtx.closePath();
- if (i == 0) {
- cCtx.fillStyle = "rgb(255,255,255)";
- cCtx.fill();
- } else {
- cCtx.stroke();
- }
- cCtx.rotate(Math.PI / 2);
- }
- cCtx.restore();
- }
- for (var i = 0; i < 2; i++) {
- cCtx.save();
- cCtx.rotate(angle * Math.PI / 180.0);
- cCtx.beginPath();
- cCtx.moveTo(0, BEARING_ARROW_WIDTH * minWidthHeight / 2);
- cCtx.lineTo(BEARING_ARROW_WIDTH * minWidthHeight / 2, 0);
- cCtx.lineTo(0, -minWidthHeight * BEARING_ARROW_LENGTH / 2);
- cCtx.lineTo(-BEARING_ARROW_WIDTH * minWidthHeight / 2, 0);
- cCtx.lineTo(0, BEARING_ARROW_WIDTH * minWidthHeight / 2);
- cCtx.closePath();
- if (i == 0) {
- cCtx.fillStyle = "rgb(238,238,0)";
- cCtx.fill();
- } else {
- cCtx.lineWidth = 3;
- cCtx.strokeStyle = "rgb(0, 0, 0)";
- cCtx.stroke();
- }
- cCtx.restore();
- }
- cCtx.restore();
-}
+ return cache_ctx;
+}
function svgPathMap(svg_path, move_fun, line_fun, curve_fun, close_fun) {
var i = 0;
@@ -127,20 +41,117 @@
} else if (svg_path[i] == "z") {
close_fun();
i++;
+ } else {
+ alert("Unknown path element: " + svg_path[i]);
}
}
}
-function drawRessie() {
- cCanvas = document.getElementById("compass");
- if (!cCanvas) {
- return;
+function drawPath(svg_path, ctx, fill, scale) {
+ if (fill) {
+ ctx.beginPath();
+ svgPathMap(svg_path, function(x, y) {ctx.moveTo(x*scale, y*scale);},
+ function(x, y) {ctx.lineTo(x*scale, y*scale);},
+ function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1*scale, y1*scale, x2*scale,
+ y2*scale, x*scale, y*scale);},
+ function() {ctx.fill();});
+ } else {
+ ctx.beginPath();
+ svgPathMap(svg_path, function(x, y) {ctx.moveTo(x*scale, y*scale);},
+ function(x, y) {ctx.lineTo(x*scale, y*scale);},
+ function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1*scale, y1*scale, x2*scale,
+ y2*scale, x*scale, y*scale);},
+ function() {ctx.stroke();});
}
- cCtx = cCanvas.getContext("2d");
- if (!cCtx) {
- return;
+}
+
+function drawCompass(ctx, scale) {
+ // draw a compass, centred at (0, 0), bounded by (-scale, -scale), (scale, scale)
+ ctx.save();
+ // draw background semi transparent filled circle
+ //ctx.lineWidth = 0.75;
+ ctx.strokeStyle = "rgb(136,136,136)";
+ ctx.fillStyle="rgba(255,255,255,0.5)";
+ ctx.beginPath();
+ ctx.arc(0, 0, CIRCLE_RADIUS * scale, 0, Math.PI * 2, true);
+ ctx.closePath();
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(0, 0, CIRCLE_RADIUS * scale, 0, Math.PI * 2, true);
+ ctx.closePath();
+ ctx.stroke();
+ // draw background N, S, E, W arrows in blue
+ var QUART = Math.sqrt(2)/2 * CIRCLE_RADIUS,
+ SVG_BACK_ARROWS = ("M 0,-" + REAR_ARROW_WIDTH + " L " + QUART + ",-" + QUART +
+ " L " + REAR_ARROW_WIDTH + ",0 L " + QUART + "," + QUART +
+ " L 0," + REAR_ARROW_WIDTH + " L -" + QUART + "," + QUART +
+ " L -" + REAR_ARROW_WIDTH + ",0 L -" + QUART + ",-" + QUART +
+ " L 0,-" + REAR_ARROW_WIDTH + " z").split(" ");
+ ctx.fillStyle = "rgb(0, 0, 255)";
+ drawPath(SVG_BACK_ARROWS, ctx, 1, scale);
+ drawPath(SVG_BACK_ARROWS, ctx, 0, scale);
+
+ var FRONT_45 = QUART * FRONT_ARROW_WIDTH * scale;
+ for (var i = 0; i < 2; i++) {
+ ctx.save();
+ for(var j=0; j<4; j++) {
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(FRONT_45, -FRONT_45);
+ ctx.lineTo(0, -scale);
+ ctx.lineTo(0, 0);
+ ctx.closePath();
+ if (i === 0) {
+ ctx.fillStyle = "rgb(255,0,0)";
+ ctx.fill();
+ } else {
+ ctx.stroke();
+ }
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(-FRONT_45, -FRONT_45);
+ ctx.lineTo(0, -scale);
+ ctx.lineTo(0, 0);
+ ctx.closePath();
+ if (i == 0) {
+ ctx.fillStyle = "rgb(255,255,255)";
+ ctx.fill();
+ } else {
+ ctx.stroke();
+ }
+ ctx.rotate(Math.PI / 2);
+ }
+ ctx.restore();
}
- cCtx.clearRect(0, 0, cCanvas.width, cCanvas.height);
+ NORTH_PATH = ("M -" + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS - LETTER_SIZE) +
+ " L -" + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS + LETTER_SIZE) +
+ " L " + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS - LETTER_SIZE) +
+ " L " + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS + LETTER_SIZE) +
+ " z").split(" ");
+ ctx.lineWidth = 3.0;
+ ctx.lineJoin = 'round';
+ ctx.strokeStyle = "rgba(255,255,255,0.9)";
+ drawPath(NORTH_PATH, ctx, 0, scale);
+ ctx.lineWidth = 1.0;
+ ctx.strokeStyle = "rgb(0,0,0)";
+ drawPath(NORTH_PATH, ctx, 0, scale);
+ ctx.restore();
+}
+
+function drawArrow(ctx, scale) {
+ ctx.save();
+ ARROW_PATH = ("M -0.05,-0.15 L 0.05,-0.15 L 0.05,0.25 L 0.1,0.25 " +
+ "L 0,0.4 L -0.1,0.25 L -0.05,0.25 L -0.05,-0.15 z").split(" ");
+ ctx.lineWidth = 1.0;
+ ctx.strokeStyle = "rgb(0,0,0)";
+ ctx.fillStyle = "rgb(238, 238, 0)";
+ ctx.lineJoin = "round";
+ drawPath(ARROW_PATH, ctx, 1, scale);
+ drawPath(ARROW_PATH, ctx, 0, scale);
+ ctx.restore();
+}
+
+function drawRessie(ctx, scale) {
var SVG_PATH=("M 242.14286,620.93361 C 242.14286,620.93361 307.14286,540.93361 318.57143,526.6479 "+
"C 330,512.36218 309.28571,498.07647 309.28571,498.07647 C 309.28571,498.07647 291.19688,481.65613 287.85714,477.36218 "+
"C 282.85715,470.93361 290.78801,462.50108 298.57143,463.79075 C 310.72728,465.80491 334.28571,463.79075 347.85714,456.6479 "+
@@ -153,7 +164,6 @@
"C 317.14286,598.79075 298.57143,603.07647 298.57143,603.07647 C 298.57143,603.07647 265,641.6479 259.28571,641.6479 "+
"C 253.57143,641.6479 243.57143,643.07647 240.71429,635.93361 C 237.85714,628.79076 242.14286,621.6479 242.14286,620.93361 z").split(" ");
var max_x = 0, max_y = 0, min_x = 2000, min_y = 2000;
- var minWidthHeight = Math.min(cCanvas.width, cCanvas.height);
function bound(x, y) {
max_x = Math.max(max_x, x);
max_y = Math.max(max_y, y);
@@ -161,27 +171,69 @@
min_y = Math.min(min_y, y);
}
svgPathMap(SVG_PATH, bound, bound, function(cx1, cy1, cx2, cy2, x, y) {bound(x, y);}, function() {});
- cCtx.save();
- if (ressie_angle < 360) {
- ressie_angle = ressie_angle + 1;
- } else {
- ressie_angle = 0;
- }
- cCtx.translate(minWidthHeight / 2, minWidthHeight / 2);
- cCtx.rotate(Math.PI / 180 * ressie_angle);
- var scale = minWidthHeight / Math.max(max_x - min_x, max_y - min_y) / Math.sqrt(2);
- cCtx.scale(scale, scale);
- cCtx.translate(-(min_x + max_x) / 2, -(min_y + max_y) / 2);
- cCtx.beginPath();
- cCtx.strokeStyle = "rgb(136, 136, 136)";
- cCtx.fillStyle = "rgb(34, 170, 238)";
- svgPathMap(SVG_PATH, function(x, y) {cCtx.moveTo(x, y);},
- function(x, y) {cCtx.lineTo(x, y);},
- function(x1, y1, x2, y2, x, y) {cCtx.bezierCurveTo(x1, y1, x2, y2, x, y);},
- function() {cCtx.closePath(); cCtx.fill();});
- svgPathMap(SVG_PATH, function(x, y) {cCtx.moveTo(x, y);},
- function(x, y) {cCtx.lineTo(x, y);},
- function(x1, y1, x2, y2, x, y) {cCtx.bezierCurveTo(x1, y1, x2, y2, x, y);},
- function() {cCtx.closePath(); cCtx.stroke();});
- cCtx.restore();
+ ctx.save();
+ //ctx.translate(minWidthHeight / 2, minWidthHeight / 2);
+// cCtx.rotate(Math.PI / 180 * ressie_angle);
+ var thisScale = scale / Math.max(max_x - min_x, max_y - min_y) * 2 / Math.sqrt(2);
+ ctx.scale(thisScale, thisScale);
+ ctx.translate(-(min_x + max_x) / 2, -(min_y + max_y) / 2);
+ ctx.beginPath();
+ ctx.strokeStyle = "rgb(136, 136, 136)";
+ ctx.fillStyle = "rgb(34, 170, 238)";
+ svgPathMap(SVG_PATH, function(x, y) {ctx.moveTo(x, y);},
+ function(x, y) {ctx.lineTo(x, y);},
+ function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1, y1, x2, y2, x, y);},
+ function() {ctx.closePath(); ctx.fill();});
+ svgPathMap(SVG_PATH, function(x, y) {ctx.moveTo(x, y);},
+ function(x, y) {ctx.lineTo(x, y);},
+ function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1, y1, x2, y2, x, y);},
+ function() {ctx.closePath(); ctx.stroke();});
+ ctx.restore();
}
+
+function drawStep() {
+ var ctx = getContext();
+ if (ctx) {
+ var ratio = (1-Math.cos(wind_step / WIND_STEPS * Math.PI))/2;
+ var angle = wind_start + (wind_end - wind_start) * ratio;
+ ctx.clearRect(0, 0, cache_canvas.width, cache_canvas.height);
+ ctx.save();
+ ctx.translate(minWidthHeight / 2, minWidthHeight / 2);
+ ctx.rotate(Math.PI * global_angle / 180);
+ drawRessie(ctx, minWidthHeight / 2);
+ ctx.restore();
+ ctx.save();
+ ctx.translate(minWidthHeight / 4, minWidthHeight / 4);
+ ctx.rotate(Math.PI * global_angle / 180);
+ drawCompass(ctx, minWidthHeight / 4);
+ ctx.restore();
+ ctx.save();
+ ctx.translate(minWidthHeight / 2, minWidthHeight / 2);
+ ctx.rotate(Math.PI * (global_angle) / 180 + angle);
+ drawArrow(ctx, minWidthHeight / 2);
+ ctx.restore();
+ }
+ if (wind_step < WIND_STEPS) {
+ wind_step = wind_step + 1;
+ } else {
+ clearInterval(wind_timer);
+ wind_timer = null;
+ wind_start = wind_end;
+ }
+}
+
+function drawWind(angle) {
+ if (last_angle && (last_angle === angle)) {
+ return;
+ }
+ last_angle = angle;
+ wind_end = angle / 180 * Math.PI;
+ if ((wind_end - wind_start) > Math.PI) {
+ wind_end = wind_end - 2 * Math.PI;
+ }
+ wind_step = 0;
+ if (wind_timer != null) {
+ clearInterval(wind_timer);
+ }
+ wind_timer = setInterval(drawStep, WIND_TIME * 1000 / WIND_STEPS);
+}
\ No newline at end of file
diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html
index 4f4b8df..3e1976a 100644
--- a/src/main/webapp/index.html
+++ b/src/main/webapp/index.html
@@ -1,9 +1,14 @@
Current Weather Conditions
-
-
- Loading...
-
+
+
+ |
+
+
+ Loading...
+
+ |
+
+
diff --git a/src/main/webapp/test.html b/src/main/webapp/test.html
index a2cccb5..61dbd46 100644
--- a/src/main/webapp/test.html
+++ b/src/main/webapp/test.html
@@ -9,9 +9,9 @@
-
+
Current Weather Conditions
-