OverlayView with canvas element

659 views
Skip to first unread message

Greg

unread,
Aug 23, 2009, 9:30:53 PM8/23/09
to Google Maps JavaScript API v3
I'm creating a RouteOverlay which uses a canvas and the
google.maps.OverlayView as its prototype. The hopeful destination for
this code will be a palm pre. I've finally gotten the canvas to draw
in an overlay of the map. However, fromLatLngToDivPixel does not seem
to give me the correct answer. Here is a copy of RouteOverlay.js

Any help and/or suggestion is, of course, appreciated.

function RouteOverlay(posArray, map) {
google.maps.OverlayView.call(this);

this.positions = posArray;
this.set_map(map);

zoomChangeListener = google.maps.event.addListener
(map,'zoom_changed',function (event) {
zoomChangeBoundsListener = google.maps.event.addListener
(map,'bounds_changed',function (event) {
this.doDraw();
google.maps.event.removeListener
(zoomChangeBoundsListener);
});
});
}

RouteOverlay.prototype = new google.maps.OverlayView();

RouteOverlay.prototype.createCanvas = function()
{
var panes = this.get_panes();
var canvas = this._canvas;

if (!canvas) {
canvas = this._canvas = document.createElement('canvas');
canvas.style.position = "absolute";
canvas.style.paddingLeft = "0px";
canvas.style.border = "0px solid none";
panes.overlayLayer.appendChild(canvas);

this._ctx = canvas.getContext("2d");
}
}

RouteOverlay.prototype.remove = function() {
if (this._canvas) {
this.set_map(null);
this._canvas.parentNode.removeChild(this._canvas);
this._canvas = null;
}
}

RouteOverlay.prototype.doDraw = function() {
this._canvas.width = this._canvas.width;
this._ctx.beginPath();

var canvasPoint;

for (var i = 0; i < this.positions.length; i++) {
canvasPoint = this.get('projection').fromLatLngToDivPixel
(this.positions[i]);

if (this.debug)
this.debug(this.positions[i]);
if (this.debug)
this.debug(canvasPoint);

if (i==0)
this._ctx.moveTo(canvasPoint.x, canvasPoint.y);
else
this._ctx.lineTo(canvasPoint.x, canvasPoint.y);
}
this._ctx.stroke();
}

RouteOverlay.prototype.draw = function(firstTime) {
this.createCanvas();

if (!this._canvas) {
return;
}
this.doDraw();
}

RouteOverlay.prototype.add_Position = function(position) {
this.positions.push(position);
}

RouteOverlay.prototype.remove = function() {
if (this._canvas)
{
this.set_map(null);
this._canvas.parentNode.removeChild(this._canvas);
this._canvas = null;
this._ctx = null;
}
}

Greg

unread,
Aug 24, 2009, 6:50:20 AM8/24/09
to Google Maps JavaScript API v3
Here is the link to the code... I did a search for and read posts
about OverlayView before posting, but did not read the 'read me before
posting' post.

http://www.bogumilfamily.com/maps/index.html



On Aug 23, 9:30 pm, Greg <gbogu...@gmail.com> wrote:
> I'm creating a RouteOverlay which uses a canvas and the
> google.maps.OverlayView as its prototype.  The hopeful destination for
> this code will be a palm pre.  I've finally gotten the canvas to draw
> in an overlay of the map.  However, fromLatLngToDivPixel does not seem
> to give me the correct answer.  Here is a link to the code http://www.bogumilfamily.com/maps/index.html

Ben Appleton

unread,
Aug 24, 2009, 10:00:11 PM8/24/09
to google-map...@googlegroups.com
Thanks for the link, we're looking into it.

Ben

Greg Bogumil

unread,
Aug 24, 2009, 10:06:14 PM8/24/09
to google-map...@googlegroups.com
Thank you Ben.  Looking forward to the response.


Susannah (Google Employee)

unread,
Aug 25, 2009, 1:05:11 AM8/25/09
to Google Maps JavaScript API v3
Hi Greg,

I got a chance to look into this today, and I don't think there's a
problem with the fromLatLngToDivPixel calculation. In the example you
gave, the second LatLng is about one degree of latitude and one degree
of longitude away from your first, which is a fairly significant
distance at zoom level 15. If you zoom out to see the whole canvas
line, it does look like it's roughly 1 degree of latitude by 1 degree
of longitude long.

As a sanity check, I made a 512 by 512 pixel map, centered at LatLng
(0,0) with zoom level 1. At this zoom level, the entire world renders
in 512 by 512 pixels. As expected, the values returned from
fromLatLngToDivPixel were:
LatLng(85, 0)* --> Point(256, 1)
LatLng(-85, 0) --> Point(256, 511)
LatLng(0, -180) --> Point(0, 256)
LatLng(0, 180) --> Point(512, 256)
*The map is bounded at approximately latitude 85.

Two other things I noticed in looking at your example:
You don't need to explicitly handle the zoom_changed and
bounds_changed events. OverlayView's draw method is called when the
map changes such that fromLatLngToDivPixel would return a new value
(e.g. on zoom or re-centering, but not drag). Also note that in your
event handlers "this" no longer refers to the OverlayView, but to the
object on which the event was fired (in this case map).

Hope this helps,
Susannah

bratliff

unread,
Aug 25, 2009, 8:16:07 AM8/25/09
to Google Maps JavaScript API v3
On Aug 25, 5:05 am, "Susannah (Google Employee)"
<susann...@google.com> wrote:

> Two other things I noticed in looking at your example:
> You don't need to explicitly handle the zoom_changed and
> bounds_changed events.

I use "bounds_changed" to stay in sync with tile replacements. The V3
"draw" method does not fire often enough. The V2 "redraw" without the
"force" argument did fire often enough.

Can you suggest another way to do it without event listeners ? I
would love it if OverlayView supported its own "bounds_changed",
"center_changed", "zoom_changed" methods without explicitly declared
event listeners on the map. Several of the methods existed once but
are no longer documented.

Susannah (Google Employee)

unread,
Aug 25, 2009, 11:56:14 PM8/25/09
to Google Maps JavaScript API v3
Hi bratliff,

Can you explain what you mean by draw not being called "often
enough"? It should be called every time the value returned from
fromLatLngToDivPixel would change (on zoom, on a call to set_center).
On a drag, the overlays are moved along with the map and do not
require repositioning. If you have an example where the overlays are
not positioned correctly without using event handlers, please post a
link.

If you actually want to refresh the OverlayViews (other than position)
when the map's center/bounds change, then the map's events should be
listened to. The center/bounds/zoom properties are not exposed on the
OverlayView, because they are properties of the map, not the overlay.

My point to Greg about the event listeners is that you should not need
to listen to the events and explicitly call draw in order to refresh
the position. In fact, that may hurt performance on some browsers.

Thanks,
Susannah

bratliff

unread,
Aug 26, 2009, 5:55:37 AM8/26/09
to Google Maps JavaScript API v3
On Aug 26, 3:56 am, "Susannah (Google Employee)"
Hi Susannah,

I am building CANVAS element tiles on the fly. I have to be able to
determine when a tile region first moves into view. With V2
GOverlays, the "redraw" method fires repeatedly during map movement.
With V3 OverlayViews, the "draw" method does not. I can work around
it but it requires an external event listener. I would like to be
able to provide to self-contained OverlayView subclass without
auxilliary event listeners.
Reply all
Reply to author
Forward
0 new messages