Question

I am working on a mapping project using Google Maps. We have a variety of different types of data that we are displaying with different geographical boundaries. Some of the data comes from the client and is very restricted in terms of privacy and cannot be sent to the server side for processing. One of the goals of our project is to interpolate the different data sets to a common regularly-sized grid for comparison and analysis. I would like to be able to visualize the grid on the map. The grid matrix is about 120x150, so about 18000 total cells with a single scalar value. This is too many polygons to render using native Google Maps drawing. Since it is a regularly sized grid, it seems like a good solution would be to render the grid as an image and overlay that on the map as a single entity. Since I cannot send the data to the server for processing, I was trying to think of a way to do this completely in javascript. I know that data-uri's can be used in css, and I believe in javascript too, to store small images as strings. I am not sure if google maps will accept this natively, but that will be a separate issue. For now I am just curious whether or not anyone has implemented a javascript image-generator using the data-uri model. And if so, how. I have searched but not found any attempts. I have looked at file specifications, but thought I'd ask here before delving too deep into a wild goose chase / reinventing the wheel. I know that I could use a canvas element to do this in a way that is makes more sense in terms of code readability, but it seems like generating a string directly, would be an elegant solution.

Was it helpful?

Solution

Thanks to some of the verbiage in the sidebar that showed up on my stackexchange question, I tried googling again with some different terms and found this:

http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/

Which more or less answers my question. Still interested of others have suggestions or answers, though!

Update:

Here is the code that I ended up using. It is modified from the link above so that the loops over the grid are done bottom-top left-right so that no flipping is necessary, and I have cut out some of the ancillary functions. In my loop, I am adjusting my data to be centered around the mean and normalized to span 4 standard deviations (two positive, two negative).

var interpolation = this.interpolateGeoDataLayerToGrid();

var numFileBytes = this.getLittleEndianHex(interpolation.grid[0].length * interpolation.grid.length);
var w = this.getLittleEndianHex(interpolation.grid[0].length);
var h = this.getLittleEndianHex(interpolation.grid.length);

var header =
    'BM' +                    // Signature
    numFileBytes +            // size of the file (bytes)*
    '\x00\x00' +              // reserved
    '\x00\x00' +              // reserved
    '\x36\x00\x00\x00' +      // offset of where BMP data lives (54 bytes)
    '\x28\x00\x00\x00' +      // number of remaining bytes in header from here (40 bytes)
    w +                       // the width of the bitmap in pixels*
    h +                       // the height of the bitmap in pixels*
    '\x01\x00' +              // the number of color planes (1)
    '\x20\x00' +              // 32 bits / pixel
    '\x00\x00\x00\x00' +      // No compression (0)
    '\x00\x00\x00\x00' +      // size of the BMP data (bytes)*
    '\x13\x0B\x00\x00' +      // 2835 pixels/meter - horizontal resolution
    '\x13\x0B\x00\x00' +      // 2835 pixels/meter - the vertical resolution
    '\x00\x00\x00\x00' +      // Number of colors in the palette (keep 0 for 32-bit)
    '\x00\x00\x00\x00';       // 0 important colors (means all colors are important)

var imgdata = "";

for (var row=interpolation.grid.length-1; row >= 0; row--) {
    for (var col=0; col<interpolation.grid[row].length; col++) {
        var value = Math.min(255,Math.max(0,Math.floor(128 + 64*(interpolation.grid[row][col]-interpolation.mean)/interpolation.stdev)));
        imgdata += String.fromCharCode(255-value, 0, value, 128);
    }
}

var datauri = 'data:image/bmp;base64,';
if(window.btoa != undefined) {
  datauri += btoa(header + imgdata);
}
else {
  datauri += $.base64.encode(header + imgdata);
}

newOverlay = new google.maps.GroundOverlay(datauri,
      new google.maps.LatLngBounds(
          new google.maps.LatLng(this.GridDataSettings.latmin, this.GridDataSettings.longmin),
          new google.maps.LatLng(this.GridDataSettings.latmax, this.GridDataSettings.longmax)
));

newOverlay.setMap(map);

And here is the lttleEndianHex helper function, as taken from the link above:

getLittleEndianHex: function(value) {
  var result = [];   
  for (var bytes = 4; bytes > 0; bytes--) {
    result.push(String.fromCharCode(value & 255));
    value >>= 8;
  }
  return result.join('');
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top