Tag Archives: weather

WMS GetFeatureInfo Request

geomet_getfeatureinfo

Continuing on with yesterday’s exploration into GeoMet and its myriad web mapping services (WMS), today I added GetFeatureInfo requests (map here).

If you’ve used WMS, you’re probably familiar with GetCapabilities (retrieves metadata) and GetMap (retrieves map tiles) requests. GetFeatureInfo is another type of request which retrieves attribute information at a given location, provided the server (e.g. GeoMet) has been configured to provide this information (look for “queryable=’1′ ” in the layer metadata).

One stumbling block I encountered (and likely handled poorly) was overcoming the issue of cross-origin resource sharing (CORS). No matter what I tried, I was blocked from retrieving the request response because, of course, my webpage resides on a different server than the WMS. I got around this by calling a PHP script that copies the text response from the request locally and reads that version. Honestly, I’m not sure why that works and reading the original request doesn’t, but it does and that’s good enough for me. If you have a simpler solution (I’m sure it’s out there), I’d love to learn about it!

Advertisements

OpenWeatherMap IDW

idwOpenWeatherMap has a nice API that allows you to consume live weather data. I have made other simple examples here (v2.1) and here (v2.0 – doesn’t work), but you should check out the OWM API documentation and examples for more.

This example (v2.5) collects weather info from several stations across British Columbia and Alberta, interpolates temperature values between the stations using the Inverse Distance Weighting method, and displays both the stations (points) and interpolated surface (raster) as PaperJS objects.

 <!DOCTYPE html>
 <html>
 <head>
 <!---------------------
 Code by Darren Wiens
 dkwiens@gmail.com
 ----------------------->
 <style type="text/css">
 html { height: 100% }
 #map { height: 500px; width: 500px; }
 canvas { position: absolute; top: 10; left: 10; z-index: 1; pointer-events:none; }
 </style>
 <!-- Load the Paper.js library -->
 <script type="text/javascript" src="http://darrenwiens.net/scripts/paper.js"></script>
 <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
 <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
 <!-- Define inlined PaperScript associate it with myCanvas -->
 <script type="text/paperscript" canvas="myCanvas">
 var maxWidth = 500;
 var maxHeight = 500;
 var maxPoint = new Point(maxWidth,maxHeight);
var rect = new Path.Rectangle(0,0,maxWidth, maxHeight);
 rect.strokeColor = 'black';
 rect.strokeWidth = 3;
var map;
 var sampleCirs = new Group();
 var texts = new Group();
 var interpRaster = new Raster('myImg');
 var minTemp = 1000;
 var maxTemp = -1000;
function onFrame(event)
 {
}
function pointToLatLng(point)
 {
 var proj = map.getProjection();
 var bounds = map.getBounds();
 var ne = bounds.getNorthEast();
 var sw = bounds.getSouthWest();
 var neWorldXY = proj.fromLatLngToPoint(ne);
 var swWorldXY = proj.fromLatLngToPoint(sw);
 var curPixelX = point.x / Math.pow(2,map.getZoom());
 var curPixelY = point.y / Math.pow(2,map.getZoom());
 var curWorldX = curPixelX + swWorldXY.x;
 var curWorldY = curPixelY + neWorldXY.y;
 var curWorldPoint = new google.maps.Point(curWorldX,curWorldY);
 var curLatLng = proj.fromPointToLatLng(curWorldPoint);
 return curLatLng;
 }
function latLngToPoint(latLng)
 {
 var proj = map.getProjection();
 var calWorldPoint = proj.fromLatLngToPoint(latLng);
 var calPixelPointx = calWorldPoint.x * Math.pow(2,map.getZoom());
 var calPixelPointy = calWorldPoint.y * Math.pow(2,map.getZoom());
 var bounds = map.getBounds();
 var ne = bounds.getNorthEast();
 var sw = bounds.getSouthWest();
 var neWorldPoint = proj.fromLatLngToPoint(ne);
 var swWorldPoint = proj.fromLatLngToPoint(sw);
 var ePixelPoint = neWorldPoint.x * Math.pow(2,map.getZoom());
 var nPixelPoint = neWorldPoint.y * Math.pow(2,map.getZoom());
 var wPixelPoint = swWorldPoint.x * Math.pow(2,map.getZoom());
 var sPixelPoint = swWorldPoint.y * Math.pow(2,map.getZoom());
 var screenPixelX = calPixelPointx - wPixelPoint;
 var screenPixelY = calPixelPointy - nPixelPoint;
 var point = new Point(screenPixelX, screenPixelY);
 return point;
 }
function drawPoints(s)
 {
 childCount = 0;
 for (var station=0;station<s.length;station++) {
 if (s[station].last.hasOwnProperty('main')) {
 if (s[station].last.main.hasOwnProperty('temp')) {
 var lat = s[station].station.coord.lat;
 var lng = s[station].station.coord.lon;
 var newPoint = new Point(latLngToPoint(new google.maps.LatLng(lat, lng)));
 sampleCirs.addChild(new Path.Circle(newPoint,2));
 sampleCirs.children[childCount].value = s[station].last.main.temp - 273.15;
 sampleCirs.children[childCount].latlng = pointToLatLng(sampleCirs.children[childCount].position);
 if (sampleCirs.children[childCount].value < minTemp) {
 minTemp = sampleCirs.children[childCount].value;
 }
 if (sampleCirs.children[childCount].value > maxTemp) {
 maxTemp = sampleCirs.children[childCount].value;
 }
 sampleCirs.strokeColor = 'black';
 sampleCirs.fillColor = 'black';
 var text = new PointText(newPoint + new Point(3,-3));
 text.content = Math.round(sampleCirs.children[childCount].value);
 text.latlng = pointToLatLng(text.position);
 texts.addChild(text);
 childCount++;
 }
 }
 }
 drawRaster();
 }
function drawRaster()
 {
 interpRaster.size = new Size(100,100);
 interpRaster.fitBounds(view.bounds);
 for (var i=0;i<100;i++)
 {
 for (var j=0;j<100;j++)
 {
 var wj = 0;
 var wis = [];
 for (var k=0;k<sampleCirs.children.length;k++)
 {
 var dx = sampleCirs.children[k].position.x - (i * 5);
 var dy = sampleCirs.children[k].position.y - (j * 5);
 var dk = Math.sqrt(Math.pow(dx,2) + Math.pow(dy,2));
 var p = 3;
 var wj_inst = 1/(Math.pow(dk,p))
 wj += wj_inst;
 wis.push(wj_inst*sampleCirs.children[k].value);
 }
 var u = 0;
 for (var l=0;l<wis.length;l++)
 {
 u += wis[l]/wj;
 }
 var scale = (u-minTemp)/(maxTemp-minTemp);
 interpRaster.setPixel(i,j,new RgbColor(scale,0,1-scale,1));
 }
 }
 interpRaster.opacity = 0.7;
 interpRaster.latlng = map.getCenter();
 interpRaster.TLlatlng = pointToLatLng(interpRaster.bounds.topLeft);
 interpRaster.BRlatlng = pointToLatLng(interpRaster.bounds.bottomRight);
 interpRaster.moveBelow(sampleCirs);
 console.log("MAX: " + maxTemp);
 console.log("MIN: " + minTemp);
 }
function getData(s){
 drawPoints(s);
 }
$(document).ready(function() {
 var style = [
 { "elementType": "geometry.fill",
 "stylers": [ { "visibility": "off" } ]
 },{ "featureType":
 "road",
 "elementType": "geometry.fill",
 "stylers": [ { "visibility": "on" },
 { "color": "#000000" } ]
 },{ "featureType": "water",
 "elementType": "geometry.fill",
 "stylers": [ { "color": "#000000" } ]
 } ]
var myLatlng = new google.maps.LatLng(53.917, -122.75);
 var myOptions = {
 zoom: 5,
 center: myLatlng,
 mapTypeId: google.maps.MapTypeId.ROADMAP,
 disableDefaultUI: true
 }
 map = new google.maps.Map(document.getElementById("map"), myOptions);
 map.setOptions({styles: style});
google.maps.event.addListener(map, 'projection_changed', function() {
 $.getJSON('http://api.openweathermap.org/data/2.5/station/find?lat=53.917&lon=-122.75&cnt=30', getData); // API v.2.5
 });
google.maps.event.addListener(map, 'center_changed', function() {
 for (var i=0;i<sampleCirs.children.length;i++)
 {
 sampleCirs.children[i].position = latLngToPoint(sampleCirs.children[i].latlng);
 sampleCirs.children[i].latlng = pointToLatLng(sampleCirs.children[i].position);
 texts.children[i].position = latLngToPoint(texts.children[i].latlng);
 texts.children[i].latlng = pointToLatLng(texts.children[i].position);
 }
 interpRaster.position = latLngToPoint(interpRaster.latlng);
 interpRaster.latlng = pointToLatLng(interpRaster.position);
 });
google.maps.event.addListener(map, 'zoom_changed', function() {
 for (var i=0;i<sampleCirs.children.length;i++)
 {
 sampleCirs.children[i].position = latLngToPoint(sampleCirs.children[i].latlng);
 sampleCirs.children[i].latlng = pointToLatLng(sampleCirs.children[i].position);
 texts.children[i].position = sampleCirs.children[i].position + new Point(3,-3);
 texts.children[i].latlng = pointToLatLng(texts.children[i].position);
 }
 var tl = latLngToPoint(interpRaster.TLlatlng);
 var br = latLngToPoint(interpRaster.BRlatlng);
 var bounds = new Rectangle(tl,br);
interpRaster.fitBounds(bounds);
 interpRaster.TLlatlng = pointToLatLng(interpRaster.bounds.topLeft);
 interpRaster.BRlatlng = pointToLatLng(interpRaster.bounds.bottomRight);
 });
 });
</script>
 </head>
 <body>
 <canvas id="myCanvas" width="500" height="500"></canvas>
 <div id="map" width="500" height="500"></div>
 <img id="myImg"></img>
 </body>
 </html>

IDW on Google Map

Image

Inspired by bad weather this afternoon, I made this basic Inverse Distance Weighted interpolator, written in JavaScript, displayed by PaperJS objects on top of a Google Map. It makes several randomly placed points with random values, then interpolates the colored surface based on the distance-weighted influence of the points. There are lots of geographic applications that may use this technique (rain, temperature surfaces, etc.), but I’m not feeling too inspired to go further right now. Let me know if you do!

Northern Rockies Highway Guide Map

Image

This was actually a project (Trans Canada Ecotour – Northern Rockies Highway Guide), not a side project. This Google Map has a few fun features: custom infowindows, custom icons, HTML elements animated with jQuery, styled map, and weather.