OverlayView with fixed postion

1,851 views
Skip to first unread message

Joan

unread,
Feb 18, 2011, 12:51:36 PM2/18/11
to Google Maps JavaScript API v3
Hi,

I'm trying to add an OverlayView using an html canvas tag.

My onAdd method looks like:
var canvas;
canvas = this.canvas_ = document.createElement('canvas');
canvas.style.position = 'fixed';
canvas.style.top = '100px';
canvas.style.left = '100px';

this.getPanes().overlayLayer.appendChild(canvas);

My problem is that when dragging the map, the canvas is not "fixed"
relative to the browser's window.

How can I achieve that?

I did try attach to canvas directly to the maps' div (map.getDiv() )
but then I loose the interaction with the map as the canvas swallows
al mouse events.

Thanks!

Esa

unread,
Feb 18, 2011, 1:33:27 PM2/18/11
to Google Maps JavaScript API v3


On Feb 18, 7:51 pm, Joan <jangl...@gmail.com> wrote:

>
>   this.getPanes().overlayLayer.appendChild(canvas);
>
> My problem is that when dragging the map, the canvas is not "fixed"
> relative to the browser's window.
>

It is not fixed to browser window but fixed to the overlayLayer pane.

The idea of overlayView is that is drags with the map like a marker.
You should rather append the canvas to map.getDiv() to keep it static.

Martin™

unread,
Feb 18, 2011, 11:51:49 PM2/18/11
to Google Maps JavaScript API v3
You might have better luck with events reaching your map if you add it
to the map as a custom control:

http://code.google.com/apis/maps/documentation/javascript/controls.html#CustomControls

Martin.

Joan

unread,
Feb 21, 2011, 5:08:45 AM2/21/11
to Google Maps JavaScript API v3
Hi,

Thanks for the responses.

Maybe I'm taking the wrong approach.

As I said, I'm trying to add a Canvas tag OverlayView. Basically what
I want to do is a Heatmap, so that I need the canvas for drawing the
heat surfaces.
For performance reasons, I obsiously can't have a canvas that covers
the entire world surface.

What I would like to do is place my canvas element to the top-left
corner every time the draw method is called.
Once called, I would like to draw the geometries that are contained
in the current map bounds.

Here's what I have:

function HeatMapOverlay(points, map) {

google.maps.OverlayView.call(this);

// Now initialize all properties.
this.points = points;
this.map_ = map;
this.canvas_ = null;

// Explicitly call setMap() on this overlay
this.setMap(map);
}

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

HeatMapOverlay.prototype.createCanvas = function()
{
var panes = this.getPanes();
var xy = this.divEl_.getXY()
var canvas = this.canvas_;
var divC = this.divC_
if (!canvas) {

canvas = this.canvas_ = document.createElement('canvas');

canvas.style.position = 'absolute';

canvas.style.top = '0px';
canvas.style.left = '0px';
canvas.style.display = 'block';

canvas.style.paddingLeft = "0px";
canvas.style.border = "0px solid none";

panes.overlayLayer.appendChild(canvas);
}
}


HeatMapOverlay.prototype.remove = function() {
if (this.canvas_) {
this.setMap(null);
this.canvas_.parentNode.removeChild(this._canvas);
this.canvas_ = null;
}
}

HeatMapOverlay.prototype.draw = function(firstTime) {
this.createCanvas();
if (!this.canvas_) {
return;
}
this.doDraw();
}


HeatMapOverlay.prototype.doDraw = function() {

var overlayProjection = this.getProjection();
var current_bounds = this.map_.getBounds();

// translate latlng bounds to pixels....
var ne =
overlayProjection.fromLatLngToDivPixel(current_bounds.getNorthEast());
var sw =
overlayProjection.fromLatLngToDivPixel(current_bounds.getSouthWest());

var width = (ne.x - sw.x)
var height = (sw.y - ne.y)


this.canvas_.width = width;
this.canvas_.height = height;
this.canvas_.style.width = width + 'px';
this.canvas_.style.height = height + 'px';

this.canvas_.style.top = '0px';
this.canvas_.style.left = '0px';

var ctx = this.canvas_.getContext('2d');
var len = this.points.length;

for (var i = 0; i< len;i++) {
var p = this.points[i];
if (current_bounds.contains(p.latlng)) {
... draw heatmap....
}
}

Is that feasible? How can I place the canvas tag to the top-left
corner every time draw is called?


@Esa:
I tried attaching the canvas directly to map.getDiv(), but it has 2
problems,

1) It swallows all mouse events, so the map can't be dragged,
2) If it could, the geometries would be wrongly placed until the draw
method was called?



Thanks!!!

On Feb 19, 5:51 am, Martin™ <warwo...@gmail.com> wrote:
> You might have better luck with events reaching your map if you add it
> to the map as a custom control:
>
> http://code.google.com/apis/maps/documentation/javascript/controls.ht...

Joan

unread,
Feb 21, 2011, 1:49:45 PM2/21/11
to Google Maps JavaScript API v3
Hi,

Finally I solved it. Maybe it's not the perfect solution, but at leat
it does the job.
Inside the draw method I remove the canvas and then I create it again
setting the convenient top and left styles.
The constructor:


function HeatMapOverlay( points, map) {
....
google.maps.event.addListener(map, 'bounds_changed',
getBufferedFunction(this.draw, this, 1250) );
}

where getBufferedFunction return a function that is called only once
in the interval:

function getBufferedFunction(f, scope, time, args) {
var canCall = true;
return function() {
if (canCall) {
setTimeout(function(){
f.apply(scope, args||[])
canCall = true;
}, time);
}
canCall = false
}
}

The draw method looks like:
HeatMapOverlay.prototype.draw = function(firstTime) {
if (this.canvas_) {
this.canvas_.parentNode.removeChild(this.canvas_);
this.canvas_ = null;
}
this.createCanvas();
if (!this.canvas_) {
return;
}
this.doDraw();
}

HeatMapOverlay.prototype.createCanvas = function()
{
var panes = this.getPanes();
var canvas = this.canvas_;
var divC = this.divC_
if (!canvas) {

canvas = this.canvas_ = document.createElement('canvas');

canvas.style.position = 'absolute';

canvas.style.top = '0px';
canvas.style.left = '0px';
canvas.style.display = 'block';

canvas.style.paddingLeft = "0px";
canvas.style.border = "0px solid none";

panes.overlayLayer.appendChild(canvas);
}
}

and doDraw looks like:

HeatMapOverlay.prototype.doDraw = function() {

var overlayProjection = this.getProjection();
var current_bounds = this.map_.getBounds();
var ne =
overlayProjection.fromLatLngToDivPixel(current_bounds.getNorthEast());
var sw =
overlayProjection.fromLatLngToDivPixel(current_bounds.getSouthWest());

var width = Math.abs(ne.x - sw.x);
var height = Math.abs(sw.y - ne.y);

if (width == 0)
width = ne.x;

if (height == 0)
height = sw.y;

// Make canvas bigger than the screen
//
var margin = {
x: width / 3,
y: height / 3
};

var canvasSize = {
width: width + margin.x * 2,
height: height + margin.y * 2
};
this.canvas_.width = canvasSize.width;
this.canvas_.height = canvasSize.height;
this.canvas_.style.width = canvasSize.width + 'px';
this.canvas_.style.height = canvasSize.height + 'px';

var xy = this.divEl_.getOffsetsTo(this.canvas_);


var offsetX = (margin.x) - xy[0];
var offsetY = (margin.y) - xy[1];

var ctx = this.canvas_.getContext('2d');
var len = this.points.length;

// for each point
for (var i = 0; i< len;i++) {
var src = this.points[i];
if (current_bounds.contains(src.lonlat)) {
.. draw....
}

//
this.canvas_.style.top = (-offsetY) + 'px';
this.canvas_.style.left = (-offsetX) + 'px';

}



Hope tit helps!

Joan
Reply all
Reply to author
Forward
0 new messages