Working with the BA3 Altus Mapping Engine in the Browser – Part 3, adding custom markers
Sunday, March 16th, 2014 at 9:38 am by — Category: Demo

In Part 2 we looked at an example of how to add simple markers with the Browser version of the BA3 Altus Mapping Engine. These markers used a simple image file to act as the representation of the marker on the screen.

What if you want to present a marker that is more complex? For example, what if you want to create text labels for the markers, or complex wind barbs in a thousand variations of angle and intensity? In these cases, you can actually draw the marker images on the fly. Here is the simplest code that behaves this way - it draws an “X” for each marker, but could just as easily draw anything else:

<!doctype html>
<html lang="en-us">
<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>BA3 Altus Mapping Engine custom marker demo</title>
</head>
<body>
<style type="text/css">
div.Altus {
  width: 100%;
  height: 900px;
  display: block;
}
</style>
<!--The map view-->
<div class="Altus" id="AltusDiv" />
<script type="text/javascript" src="http://dev.ba3.us/js/altus.js"></script>
<script type='text/javascript'>
var mapView = new Altus(document.getElementById('AltusDiv'));
// initializing the base map
if (mapView.addInternetMap != null) {
  mapView.addInternetMap("baseMap","http://otile1.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg");
}
// Returns a canvas that can be used for drawing
// Used by the addMarkerLabel function
function createCanvas(width, height) {
  var canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  return canvas;
}
// defining a function to receive marker tap events. This must exist in some form or app stalls
var onDynamicMarkerTapped = function (mapName, markerName, screenX, screenY, markerX, markerY) {
  console.log("You tapped (or clicked) dynamic marker " + markerName +
    " on map " + mapName +
    " at screen point(" + screenX + "," + screenY + ")" +
    " at marker point (" + markerX + "," + markerY + ").");
};
/////////////////////////////////////////////////////////////////////////
// Draws a label to a canvas, then adds it as a dynamic marker.
// mapName - Name of dynamic map. i.e. "Places"
// markerName - Unique name for marker. i.e. "323"
// labelText - The text want to use fo the marker. i.e. "Raleigh"
// fontName - Name of font to us
// fontSize - Point size of font to use
// lon, lat - Geographic location
// Tips: You can spice up this funciton using different font names, sizes
// colors etc.
var addMarkerLabel = function (altusMapView, mapName, markerName, labelText, fontName, fontSize, lat, lon)
{
  var canvas = createCanvas(16,16);//document.getElementById('myCanvas');
  var context = canvas.getContext('2d');
  var width = canvas.width;
  var height = canvas.height;
  //Clear
  context.clearRect(0,0,width,height);
  //Draw the marker (you can draw anything you like here)
  context.fillStyle = "rgba(255,0,0,255)";
  context.strokeStyle = "rgba(255,0,0,255)";
  context.beginPath();
  context.moveTo(0,height);
  context.lineTo(width,0);
  context.moveTo(0,0);
  context.lineTo(width,height);
  context.stroke();
  context.strokeRect(0,0,width,height);
  //Get image data from the context
  var imgd = context.getImageData(0, 0, width, height);
  //Compute size
  var numBytes = width * height * 4;
  //Allocate memory in mapping engine
  var ptr= altusMapView.Module._malloc(numBytes);
  var heapBytes= new Uint8Array(altusMapView.Module.HEAPU8.buffer, ptr, numBytes);
  //Copy image data into mapping engine memory
  heapBytes.set(new Uint8Array(imgd.data));
  //Add the marker
  altusMapView.addDynamicMarkerWithImageData(mapName, markerName,
    lon, lat, //Location
    width/2, height/2, //Anchor point
    heapBytes.byteOffset, //Memory location
    width, height); //Image size
  //Free the memory we allocated
  altusMapView.Module._free(heapBytes.byteOffset);
};
function pageLoaded()
{
  //Add some marker labels
  mapView.addDynamicMarkerMap("Places");
  var fontName = "Arial";
  var fontSize = 12;
  addMarkerLabel(mapView, "Places", "1", "Austin", fontName, fontSize,
    30.266925,-97.741268);
  addMarkerLabel(mapView, "Places", "2", "Corpus Christi", fontName, fontSize,
    26.917172, -97.636356);
  addMarkerLabel(mapView, "Places", "3", "Los Angeles", fontName, fontSize,
    34.048108,-118.251557);
  addMarkerLabel(mapView, "Places", "4", "Seattle", fontName, fontSize,
    47.60107,-122.331498);
  addMarkerLabel(mapView, "Places", "5", "Tampa", fontName, fontSize,
    27.934967,-82.460847);
  addMarkerLabel(mapView, "Places", "6", "Denver", fontName, fontSize,
    39.736762,-104.989579);
  addMarkerLabel(mapView, "Places", "7", "Chicago", fontName, fontSize,
    41.864447,-87.628541);
  addMarkerLabel(mapView, "Places", "8", "Raleigh", fontName, fontSize,
    35.784468,-78.682206);
  addMarkerLabel(mapView, "Places", "9", "San Francisco", fontName, fontSize,
    37.801511,-122.473896);
  addMarkerLabel(mapView, "Places", "10", "New York", fontName, fontSize,
    40.744656,-73.994401);
};
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
} else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}
addLoadEvent(pageLoaded);
</script>
</body>
</html>

If you run this HTML file, you will see something like this:

custom-markers

In place of the “X”s, you can draw anything you like. Play around with it and you will see the possibilities.

You can even draw text labels for markers. In the above code, swap out the function that draws the markers with this code:

/////////////////////////////////////////////////////////////////////////
// Draws a label to a canvas, then adds it as a dynamic marker.
// mapName - Name of dynamic map. i.e. "Places"
// markerName - Unique name for marker. i.e. "323"
// labelText - The text want to use fo the marker. i.e. "Raleigh"
// fontName - Name of font to us
// fontSize - Point size of font to use
// lon, lat - Geographic location
// Tips: You can spice up this funciton using different font names, sizes
// colors etc.
var addMarkerLabel = function (altusMapView, mapName, markerName, labelText, fontName, fontSize, lat, lon)
{
  var canvas = createCanvas(256,256);//document.getElementById('myCanvas');
  var context = canvas.getContext('2d');
  var width = canvas.width;
  var height = canvas.height;
  //Clear
  context.clearRect(0,0,width,height);
  //Draw the text
  var x = width / 2;
  var y = height / 2;
  context.font = fontSize+'pt '+fontName;
  context.textAlign = 'center';
  context.fillStyle = "rgba(255,0,0,255)";
  context.fillText(labelText, x, y);
  //Grab only the needed pixels of the canvas for the marker image
  //To this we need to measure the text (this can be refined a bit more
  //but I can't figure out an accurate text height)
  var metrics = context.measureText(labelText);
  var textWidth = metrics.width;
  var textHeight = metrics.height;
  var startX = Math.round(x - textWidth/2)-1;
  var startY = Math.round(y - fontSize)-1;
  var imageWidth = Math.round(textWidth)+1;
  var imageHeight = Math.round(fontSize+fontSize/2)+1;
  //Get image data from the context
  var imgd = context.getImageData(startX, startY, imageWidth, imageHeight);
  //Compute size
  var numBytes = imageWidth * imageHeight * 4;
  //Allocate memory in mapping engine
  var ptr= altusMapView.Module._malloc(numBytes);
  var heapBytes= new Uint8Array(altusMapView.Module.HEAPU8.buffer, ptr, numBytes);
  //Copy image data into mapping engine memory
  heapBytes.set(new Uint8Array(imgd.data));
  //Add the marker
  altusMapView.addDynamicMarkerWithImageData(mapName, markerName,
    lon, lat, //Location
    imageWidth/2, imageHeight/2, //Anchor point
    heapBytes.byteOffset, //Memory location
    imageWidth, imageHeight); //Image size
  //Free the memory we allocated
  altusMapView.Module._free(heapBytes.byteOffset);
};

When you run this code, you will see 10 labels over the 10 chosen cities:

marker-text

 

Learn More!


If you have questions about Altus products and services, the demonstration code or licensing, please contact us at: [email protected]. Also, any feedback, comments or suggestions that you have are always greatly appreciated.