Something that has been on my backlog for some time is trying to mix Bing Maps and WebGL, similarly to what I've done for an "old" Google Maps experiment.
That previous demo was done on top of a Google maps sample, hence just requiring some small tweaks and improvements. Also, was very low-level and not really practical to adapt to more "real-world" usage, as it required programming the shaders, computing the transformation matrixes, etc.
Thus, I was trying to find a alternative WebGL JS lib that was:
IvanK Lib is pretty good (and fast) but Pixi.js takes the cake with tons of functionality and a large community using it.
I'm going to enumerate the various experiments I did, showing a sample page for each.
Recommendation: use Chrome as otherwise it might be painfully slow/non-working.
1. Create a pixi stage on top of Bing Maps.
http://psousa.net/demos/bingmaps/webgl/pixi/pixi1.html
Yep, nothing visible. Regardless, if you open a DOM inspector you can see a canvas element that was generated on top of the map.
![]()
2. Add a sprite to the map.
http://psousa.net/demos/bingmaps/webgl/pixi/pixi2.html
![]()
3. Listen to the viewchange event and update the sprite position
http://psousa.net/demos/bingmaps/webgl/pixi/pixi3.html
http://psousa.net/demos/bingmaps/webgl/pixi/pixi4.html
Depending on your machine (and graphics card) should still behave nicely. Regardless, when displaying lots of similar sprites pixi.js supports the concept of SpriteBatch:
http://psousa.net/demos/bingmaps/webgl/pixi/pixi5.html
6. Scale the SpriteBatch instead of reposition individual sprites
http://psousa.net/demos/bingmaps/webgl/pixi/pixi6.html
An improved solution would be to use this mechanism on panning/zooming, and having different LOD (Level-of-Detail) Sprites, which would be redrawn when the zoom animation finished.
Now, instead of drawing sprites I'm going to show how to draw primitives (in this case rectangles).
7. Draw primitives
http://psousa.net/demos/bingmaps/webgl/pixi/pixi7.html
All of this is obviously non-production code with various bugs. Regardless, future looks promising :)
That previous demo was done on top of a Google maps sample, hence just requiring some small tweaks and improvements. Also, was very low-level and not really practical to adapt to more "real-world" usage, as it required programming the shaders, computing the transformation matrixes, etc.
Thus, I was trying to find a alternative WebGL JS lib that was:
- Fast
- Easy to use, albeit still providing some low-level control, namely on primitives drawing
IvanK Lib is pretty good (and fast) but Pixi.js takes the cake with tons of functionality and a large community using it.
I'm going to enumerate the various experiments I did, showing a sample page for each.
Recommendation: use Chrome as otherwise it might be painfully slow/non-working.
1. Create a pixi stage on top of Bing Maps.
http://psousa.net/demos/bingmaps/webgl/pixi/pixi1.html
var mapDiv = map.getRootElement();
stage = new PIXI.Stage();
// create a renderer instance mapping (pun intended) the size of the map.
renderer = PIXI.autoDetectRenderer(
map.getWidth(),
map.getHeight(),
{transparent: true});
// add the renderer view element to the DOM, making it sit on top of the map
mapDiv.parentNode.lastChild.appendChild(renderer.view);
renderer.view.style.position = "absolute";
renderer.view.style.top = "0px";
renderer.view.style.left = "0px";
renderer.render(stage);
Yep, nothing visible. Regardless, if you open a DOM inspector you can see a canvas element that was generated on top of the map.

2. Add a sprite to the map.
http://psousa.net/demos/bingmaps/webgl/pixi/pixi2.html
var texture = PIXI.Texture.fromImage("img/bunny.png");Although the bunny is properly added on top of the map it's not georeferenced. Thus, if the map is moved the bunny stays on the same screen position.
var bunny = new PIXI.Sprite(texture);
// center the sprite anchor point
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
bunny.lat = 40.0;
bunny.lon = -8.5;
var pixelCoordinate = map.tryLocationToPixel(
new MM.Location(bunny.lat, bunny.lon),
MM.PixelReference.control);
bunny.position.x = pixelCoordinate.x;
bunny.position.y = pixelCoordinate.y;
stage.addChild(bunny);
3. Listen to the viewchange event and update the sprite position
http://psousa.net/demos/bingmaps/webgl/pixi/pixi3.html
MM.Events.addHandler(map, 'viewchange', updatePosition);4. Do the same thing for 1000 sprites
(...)
function updatePosition(e) {
var pixelCoordinate = map.tryLocationToPixel(
new MM.Location(bunny.lat, bunny.lon),
MM.PixelReference.control);
bunny.position.x = pixelCoordinate.x;
bunny.position.y = pixelCoordinate.y;
renderer.render(stage);
}
http://psousa.net/demos/bingmaps/webgl/pixi/pixi4.html
Depending on your machine (and graphics card) should still behave nicely. Regardless, when displaying lots of similar sprites pixi.js supports the concept of SpriteBatch:
The SpriteBatch class is a really fast version of the DisplayObjectContainer built solely for speed, so use when you need a lot of sprites or particles5. Use SpriteBatch
http://psousa.net/demos/bingmaps/webgl/pixi/pixi5.html
container = new PIXI.SpriteBatch();It's really simple to use. Instead of adding the sprites to the stage add them to a SpriteBatch. Now, the problem is that this code is still updating the position of each individual sprite when moving/zooming the map.
stage.addChild(container);
for (var i = 0; i < 1000; i++) {
var bunny = new PIXI.Sprite(texture);
// center the sprites anchor point
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
// move the sprite t the center of the screen
bunny.lat = 40.0 + Math.random() * 20;
bunny.lon = -8.5 + Math.random() * 50;
var pixelCoordinate = map.tryLocationToPixel(
new MM.Location(bunny.lat, bunny.lon),
MM.PixelReference.control);
bunny.position.x = pixelCoordinate.x;
bunny.position.y = pixelCoordinate.y;
container.addChild(bunny);
bunnies.push(bunny);
}
6. Scale the SpriteBatch instead of reposition individual sprites
http://psousa.net/demos/bingmaps/webgl/pixi/pixi6.html
function updatePosition(e) {This sample doesn't update the individual sprites and scales the SpriteBatch as a whole. This provides a good performance impact, although the sprites will look pixelated on higher zoom levels.
if(!e.linear) //zooming animation
{
var currentWidth = getCurrentWidth();
var diff = startWidth / currentWidth;
container.scale.x = diff;
container.scale.y = diff;
var divTopLeft = map.tryLocationToPixel(startPosition, MM.PixelReference.control);
var x = divTopLeft.x;
var y = divTopLeft.y;
container.position.x = x;
container.position.y = y;
renderer.render(stage);
}
}
An improved solution would be to use this mechanism on panning/zooming, and having different LOD (Level-of-Detail) Sprites, which would be redrawn when the zoom animation finished.
Now, instead of drawing sprites I'm going to show how to draw primitives (in this case rectangles).
7. Draw primitives
http://psousa.net/demos/bingmaps/webgl/pixi/pixi7.html
graphics = new PIXI.Graphics();I'm basically creating 20000 small rectangles using pixi.js. On higher zoom levels precision isn't lost as this is vector data (as opposed to the raster data from the previous examples).
var referencePixel = map.tryLocationToPixel({ latitude: 44, longitude: -9.5}, MM.PixelReference.control);
graphics.beginFill(0xFFFFFF);
for(var i=0; i < 20000; i++) {
graphics.drawRect(referencePixel.x + Math.random()* 1200.0, referencePixel.y + Math.random()*900.0, 2, 2);
}
graphics.endFill();
All of this is obviously non-production code with various bugs. Regardless, future looks promising :)