Actually, the trick is to patch the map's setBaseLayer() function.
I have some code here, but it's rather old and I haven't had time to look at it properly.
OpenLayers.Map.prototype.setBaseLayer = function(newBaseLayer) {
var oldExtent = null;
if (this.baseLayer)
{
oldExtent = this.baseLayer.getExtent();
if (this.baseLayer.projection.projCode != newBaseLayer.projection.projCode)
{
var lb = new OpenLayers.Geometry.Point(oldExtent.left, oldExtent.bottom);
var rt = new OpenLayers.Geometry.Point(oldExtent.right, oldExtent.top);
OpenLayers.Projection.transform(lb, this.baseLayer.projection, newBaseLayer.projection);
OpenLayers.Projection.transform(rt, this.baseLayer.projection, newBaseLayer.projection);
oldExtent.left = lb.x;
oldExtent.bottom = lb.y;
oldExtent.right = rt.x;
oldExtent.top = rt.y;
}
}
if (newBaseLayer != this.baseLayer)
{
// ensure newBaseLayer is already loaded
if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
// preserve center and scale when changing base layers
var center = this.getCenter();
var newResolution = OpenLayers.Util.getResolutionFromScale(this.getScale(), newBaseLayer.units);
// make the old base layer invisible
if (this.baseLayer != null && !this.allOverlays)
{
this.baseLayer.setVisibility(false);
}
var oldBaseLayer = this.baseLayer;
// set new baselayer
this.baseLayer = newBaseLayer;
// Increment viewRequestID since the baseLayer is
// changing. This is used by tiles to check if they should
// draw themselves.
this.viewRequestID++;
if(!this.allOverlays || this.baseLayer.visibility)
{
this.baseLayer.setVisibility(true);
}
this.maxExtent = this.baseLayer.maxExtent;
//this.projection = this.baseLayer.projection.projCode;
/*
this.units = this.baseLayer.units;
this.maxResolution = this.baseLayer.maxResolution;
this.minResolution = this.baseLayer.minResolution;
this.numZoomLevels = this.baseLayer.numZoomLevels;
*/
// recenter the map
if (center != null)
{
if (this.baseLayer.projection.projCode != oldBaseLayer.projection.projCode)
{
var ct = new OpenLayers.Geometry.Point(center.lon, center.lat);
OpenLayers.Projection.transform(ct, oldBaseLayer.projection, this.baseLayer.projection);
center.lon = ct.x;
center.lat = ct.y;
//Dump other map parameters?
//this.units = this.baseLayer.units;
//this.maxExtent = this.baseLayer.maxExtent;
//this.maxResolution = this.baseLayer.maxResolution;
//this.numZoomLevels = this.baseLayer.numZoomLevels;
//this.projection = this.baseLayer.projection;
//Reproject any features. (Any way of doing this with one function call?)
var vecLayers = objMap.getLayersByClass('OpenLayers.Layer.Vector');
if (vecLayers != null)
{
for (i = 0; i < vecLayers.length; i++)
{
var arrFeat = vecLayers[i].features;
for (j = 0; j < arrFeat.length; j++)
{
arrFeat[j].geometry.transform(oldBaseLayer.projection, this.baseLayer.projection);
}
vecLayers[i].redraw(); //Seems to be necessary for marker.
}
}
//Need to reset maxExtent to redraw WMS layer.
//TODO: need to switch to version of layer that matches new projection, in order
//to avoid reprojecting.
var wmsLayers = this.getLayersByClass('OpenLayers.Layer.WMS');
if (wmsLayers != null)
{
for (i = 0; i < wmsLayers.length; i++)
{
//Get layer names.
wmsLayers[i].maxExtent = this.maxExtent;
}
}
}
// new zoom level derived from old scale
var newZoom = this.getZoomForResolution(newResolution || this.resolution, true);
// zoom and force zoom change
this.setCenter(center, newZoom, false, true);
}
this.events.triggerEvent("changebaselayer", {
layer: this.baseLayer
});
}
}
}