[OpenLayers-Dev] {Filename?} addition to issue #1666;
Multiple layers for ModifyFeature
Kris Geusebroek
kgeusebroek at xebia.com
Thu Feb 19 08:35:24 EST 2009
Skipped content of type multipart/alternative-------------- next part --------------
OpenLayers.Control.MultipleLayersSelectFeature=OpenLayers.Class(OpenLayers.Control,{
multipleKey:null,
toggleKey:null,
multiple:false,
clickout:true,
toggle:false,
hover:false,
box:false,
onSelect:function(){},
onUnselect:function(){},
geometryTypes:null,
layer:null,
layers:null,
callbacks:null,
selectStyle:null,
renderIntent:"select",
handlers:null,
initialize:function(layers,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);
if(!(layers instanceof Array)){layers=[layers];}
this.layers=layers;
this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,{displayInLayerSwitcher:false,display:function(){},getFeatureFromEvent:function(evt){var feature;for(var i=0;i<layers.length;i++){feature=layers[i].getFeatureFromEvent(evt);if(feature){return feature;}}}});
var callbacks={click:this.clickFeature,clickout:this.clickoutFeature};
if(this.hover){callbacks.over=this.overFeature;callbacks.out=this.outFeature;}
this.callbacks=OpenLayers.Util.extend(callbacks,this.callbacks);
this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};
if(this.box){this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"});}},
destroy:function(){OpenLayers.Control.prototype.destroy.apply(this, arguments);
this.layer.destroy();},
activate:function(){
if(!this.active){
this.collectRoots();
this.map.addLayer(this.layer);
this.map.events.register("changelayer",this,this.handleChangeLayer);
this.handlers.feature.activate();
if(this.box&&this.handlers.box){this.handlers.box.activate();}
}
return OpenLayers.Control.prototype.activate.apply(this,arguments);
},
deactivate:function(){
if(this.active){
this.handlers.feature.deactivate();
if(this.handlers.box){this.handlers.box.deactivate();}
this.map.events.unregister("changelayer",this,this.handleChangeLayer);
this.resetRoots();
this.map.removeLayer(this.layer);
}
return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
},
unselectAll:function(options){
var layer,feature;
for(var l=0;l<this.layers.length;++l){
layer=this.layers[l];
for(var i=layer.selectedFeatures.length-1;i>=0;--i){
feature=layer.selectedFeatures[i];
if(!options||options.except!=feature){
this.unselect(feature);
}
}
}
},
clickFeature:function(feature){
if(!this.hover){
var selected=(OpenLayers.Util.indexOf(feature.layer.selectedFeatures,feature)>-1);
if(selected){
if(this.toggleSelect()){
this.unselect(feature);
}
else if(!this.multipleSelect()){
this.unselectAll({except:feature});
}
}
else{
if(!this.multipleSelect()){
this.unselectAll({except:feature});
}
this.select(feature);
}
}
},
multipleSelect:function(){return this.multiple||this.handlers.feature.evt[this.multipleKey];},
toggleSelect:function(){return this.toggle||this.handlers.feature.evt[this.toggleKey];},
clickoutFeature:function(feature){
if(!this.hover&&this.clickout){
this.unselectAll();
}
},
overFeature:function(feature){
if(this.hover&&(OpenLayers.Util.indexOf(feature.layer.selectedFeatures,feature)==-1)){
this.select(feature);
}
},
outFeature:function(feature){
if(this.hover){
this.unselect(feature);
}
},
select:function(feature){
var layer=feature.layer;
if (layer) {
var cont=layer.events.triggerEvent("beforefeatureselected",{feature:feature});
if(cont!==false){
layer.selectedFeatures.push(feature);
var selectStyle=this.selectStyle||this.renderIntent;
layer.drawFeature(feature,selectStyle);
layer.events.triggerEvent("featureselected",{feature:feature});
this.onSelect(feature);
}
}
},
unselect:function(feature){
var layer=feature.layer;
layer.drawFeature(feature,"default");
OpenLayers.Util.removeItem(layer.selectedFeatures,feature);
layer.events.triggerEvent("featureunselected",{feature:feature});
this.onUnselect(feature);
},
selectBox:function(position){
if(position instanceof OpenLayers.Bounds){
var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));
var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));
var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);
if(!this.multipleSelect()){
this.unselectAll();
}
var prevMultiple=this.multiple;
this.multiple=true;
var layer;
for(var l=0;l<this.layers.length;++l){
layer=this.layers[l];
for(var i=0,len=layer.features.length;i<len;++i){
var feature=layer.features[i];
if(this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1){
if(bounds.toGeometry().intersects(feature.geometry)){
if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){
this.select(feature);
}
}
}
}
}
this.multiple=prevMultiple;
}
},
setMap:function(map){
this.handlers.feature.setMap(map);
if(this.box){this.handlers.box.setMap(map);}
OpenLayers.Control.prototype.setMap.apply(this,arguments);
},
collectRoots:function(){
var layer;
for(var i=0;i<this.map.layers.length;++i){
layer=this.map.layers[i];
if(OpenLayers.Util.indexOf(this.layers,layer)!=-1){
layer.renderer.moveRoot(this.layer.renderer);
}
}
},
resetRoots:function(){
var layer;
for(var i=0;i<this.layers.length;++i){
layer=this.layers[i];
if(layer.renderer.getRenderLayer()==this.layer){
this.layer.renderer.moveRoot(layer.renderer);
}
}
},
handleChangeLayer:function(evt){
var layer=evt.layer;
if(evt.property=="order"&&OpenLayers.Util.indexOf(this.layers,layer)!=-1){
this.resetRoots();
this.collectRoots();
}
},
CLASS_NAME:"OpenLayers.Control.MultipleLayersSelectFeature"
});
OpenLayers.Control.MultipleLayersModifyFeature=OpenLayers.Class(OpenLayers.Control,{
geometryTypes:null,
clickout:true,
toggle:true,
layer:null,
feature:null,
vertices:null,
virtualVertices:null,
selectControl:null,
dragControl:null,
handlers:null,
deleteCodes:null,
virtualStyle:null,
mode:null,
radiusHandle:null,
dragHandle:null,
onModificationStart:function(){},
onModification:function(){},
onModificationEnd:function(){},
layers:null,
initialize:function(layers,options){
if(!(layers instanceof Array)) {
layers=[layers];
}
this.layers=layers;
this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,{
displayInLayerSwitcher:false,
display:function(){},
getFeatureFromEvent:function(evt) {
var feature;
for(var i=0;i<layers.length;i++) {
feature=layers[i].getFeatureFromEvent(evt);
if(feature){
return feature;
}
}
}
});
this.vertices=[];
this.virtualVertices=[];
this.virtualStyle=OpenLayers.Util.extend({},this.layers[0].style||this.layers[0].styleMap.createSymbolizer());
this.virtualStyle.fillOpacity=0.3;
this.virtualStyle.strokeOpacity=0.3;
this.deleteCodes=[46,68];
this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;
OpenLayers.Control.prototype.initialize.apply(this, [options]);
if(!(this.deleteCodes instanceof Array)){
this.deleteCodes=[this.deleteCodes];
}
var control=this;
var selectOptions={geometryTypes:this.geometryTypes,clickout:this.clickout,toggle:this.toggle};
this.selectControl=new OpenLayers.Control.MultipleLayersSelectFeature(this.layers,selectOptions);
for(var i=0;i<this.layers.length;i++) {
this.layers[i].events.on({
"beforefeatureselected":this.beforeSelectFeature,
"featureselected":this.selectFeature,
"featureunselected":this.unselectFeature,
/* Added eventhandling to prevent a feature being registered if layer is reloaded */"loadstart":this.unselectFeature,
scope:this
});
}
var dragOptions={/* Removed geometryType Point to enable draging of other types. Was: geometryTypes:["OpenLayers.Geometry.Point"]*/geometryTypes:null,
snappingOptions:this.snappingOptions,
onStart:function(feature,pixel){control.dragStart.apply(control,[feature,pixel]);},
onDrag:function(feature){control.dragVertex.apply(control,[feature]);},
onComplete:function(feature){control.dragComplete.apply(control,[feature]);}
};
this.dragControl=new OpenLayers.Control.MultipleLayersDragFeature(this.layers[0],dragOptions);
var keyboardOptions={keydown:this.handleKeypress};
this.handlers={keyboard:new OpenLayers.Handler.Keyboard(this,keyboardOptions)};
},
destroy:function(){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].events.un({
"beforefeatureselected":this.beforeSelectFeature,
"featureselected":this.selectFeature,
"featureunselected":this.unselectFeature,
/* Added eventhandling to prevent a feature being registered if layer is reloaded */"loadstart":this.unselectFeature,
scope:this
});
}
this.layer.destroy();
this.selectControl.destroy();
this.dragControl.destroy();
OpenLayers.Control.prototype.destroy.apply(this,[]);
},
activate:function(){
return(this.selectControl.activate()&&this.handlers.keyboard.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},
deactivate:function(){
var deactivated=false;
if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].removeFeatures(this.vertices,{silent:true});
this.layers[i].removeFeatures(this.virtualVertices,{silent:true});
}
this.vertices=[];
this.dragControl.deactivate();
if(this.feature&&this.feature.geometry){
this.selectControl.unselect.apply(this.selectControl,[this.feature]);
}
this.selectControl.deactivate();
this.handlers.keyboard.deactivate();
deactivated=true;
}
return deactivated;
},
beforeSelectFeature:function(object){
return object.feature.layer.events.triggerEvent("beforefeaturemodified",{feature:object.feature});
},
selectFeature:function(object){
this.feature=object.feature;
this.resetVertices();
this.dragControl.activate(this.feature.layer);
this.onModificationStart(this.feature);
},
unselectFeature:function(object){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].removeFeatures(this.vertices,{silent:true});
this.layers[i].destroyFeatures(this.virtualVertices,{silent:true});
}
this.vertices=[];
this.virtualVertices=[];
if(this.dragHandle){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].destroyFeatures([this.dragHandle],{silent:true});
}
delete this.dragHandle;
}
if(this.radiusHandle){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].destroyFeatures([this.radiusHandle],{silent:true});
}
delete this.radiusHandle;
}
this.feature=null;
this.dragControl.deactivate();
this.onModificationEnd(object.feature);
for(var i=0;i<this.layers.length;i++) {
this.layers[i].events.triggerEvent("afterfeaturemodified",{feature:object.feature});
}
},
dragStart:function(feature,pixel){
if(feature!=this.feature&&!feature.geometry.parent&&feature!=this.dragHandle&&feature!=this.radiusHandle){
if(this.feature){
this.selectControl.clickFeature.apply(this.selectControl,[this.feature]);
}
if(this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)!=-1){
this.selectControl.clickFeature.apply(this.selectControl,[feature]);
this.dragControl.overFeature.apply(this.dragControl,[feature]);
this.dragControl.lastPixel=pixel;
this.dragControl.handlers.drag.started=true;
this.dragControl.handlers.drag.start=pixel;
this.dragControl.handlers.drag.last=pixel;
}
}
},
dragVertex:function(vertex){
if(this.feature.geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){
if(this.feature!=vertex){
this.feature=vertex;
}
}else{
if(vertex._index){
vertex.geometry.parent.addComponent(vertex.geometry,vertex._index);
delete vertex._index;
OpenLayers.Util.removeItem(this.virtualVertices,vertex);
this.vertices.push(vertex);
}else if(
vertex==this.dragHandle){
this.feature.layer.removeFeatures(this.vertices,{silent:true});
this.vertices=[];
if(this.radiusHandle){
this.feature.layer.destroyFeatures([this.radiusHandle],{silent:true});
this.radiusHandle=null;
}
}
if(this.virtualVertices.length>0){
this.feature.layer.destroyFeatures(this.virtualVertices,{silent:true});
this.virtualVertices=[];
}
this.feature.layer.drawFeature(this.feature,this.selectControl.renderIntent);
}
this.feature.layer.drawFeature(vertex);
},
dragComplete:function(vertex){
this.resetVertices();
this.onModification(this.feature);
this.feature.layer.events.triggerEvent("featuremodified",{feature:this.feature});
},
resetVertices:function(){
if(this.dragControl.feature){
this.dragControl.outFeature(this.dragControl.feature);
}
if(this.vertices.length>0){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].removeFeatures(this.vertices,{silent:true});
}
this.vertices=[];
}
if(this.virtualVertices.length>0){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].removeFeatures(this.virtualVertices,{silent:true});
}
this.virtualVertices=[];
}
if(this.dragHandle){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].destroyFeatures([this.dragHandle],{silent:true});
}
this.dragHandle=null;
}
if(this.radiusHandle){
for(var i=0;i<this.layers.length;i++) {
this.layers[i].destroyFeatures([this.radiusHandle],{silent:true});
}
this.radiusHandle=null;
}
if(this.feature&&this.feature.geometry.CLASS_NAME!="OpenLayers.Geometry.Point"){
if((this.mode&OpenLayers.Control.ModifyFeature.DRAG)){
this.collectDragHandle();
}
if((this.mode&(OpenLayers.Control.ModifyFeature.ROTATE|OpenLayers.Control.ModifyFeature.RESIZE))){
this.collectRadiusHandle();
}
if((this.mode&OpenLayers.Control.ModifyFeature.RESHAPE)){
this.collectVertices();
}
}
},
handleKeypress:function(evt){
var code=evt.keyCode;
if(this.feature&&OpenLayers.Util.indexOf(this.deleteCodes,code)!=-1){
var vertex=this.dragControl.feature;
if(vertex&&OpenLayers.Util.indexOf(this.vertices,vertex)!=-1&&!this.dragControl.handlers.drag.dragging&&vertex.geometry.parent){
vertex.geometry.parent.removeComponent(vertex.geometry);
this.feature.layer.drawFeature(this.feature,this.selectControl.renderIntent);
this.resetVertices();
this.onModification(this.feature);
this.feature.layer.events.triggerEvent("featuremodified",{feature:this.feature});
}
}
},
collectVertices:function(){
this.vertices=[];
this.virtualVertices=[];
var control=this;
function collectComponentVertices(geometry){
var i,vertex,component,len;
if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){
vertex=new OpenLayers.Feature.Vector(geometry);
control.vertices.push(vertex);
}else{
var numVert=geometry.components.length;
if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){
numVert-=1;
}
for(i=0;i<numVert;++i){
component=geometry.components[i];
if(component.CLASS_NAME=="OpenLayers.Geometry.Point"){
vertex=new OpenLayers.Feature.Vector(component);
control.vertices.push(vertex);
}else{
collectComponentVertices(component);
}
}
if(geometry.CLASS_NAME!="OpenLayers.Geometry.MultiPoint"){
for(i=0,len=geometry.components.length;i<len-1;++i){
var prevVertex=geometry.components[i];
var nextVertex=geometry.components[i+1];
if(prevVertex.CLASS_NAME=="OpenLayers.Geometry.Point"&&nextVertex.CLASS_NAME=="OpenLayers.Geometry.Point"){
var x=(prevVertex.x+nextVertex.x)/2;
var y=(prevVertex.y+nextVertex.y)/2;
var point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(x,y),null,control.virtualStyle);
point.geometry.parent=geometry;
point._index=i+1;
control.virtualVertices.push(point);
}
}
}
}
}
collectComponentVertices.call(this,this.feature.geometry);
this.feature.layer.addFeatures(this.virtualVertices,{silent:true});
this.feature.layer.addFeatures(this.vertices,{silent:true});
},
collectDragHandle:function(){
var geometry=this.feature.geometry;
var center=geometry.getBounds().getCenterLonLat();
var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);
var origin=new OpenLayers.Feature.Vector(originGeometry);
originGeometry.move=function(x,y){
OpenLayers.Geometry.Point.prototype.move.call(this,x,y);
geometry.move(x,y);
};
this.dragHandle=origin;
this.feature.layer.addFeatures([this.dragHandle],{silent:true});
},
collectRadiusHandle:function(){
var geometry=this.feature.geometry;
var bounds=geometry.getBounds();
var center=bounds.getCenterLonLat();
var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);
var radiusGeometry=new OpenLayers.Geometry.Point(bounds.right,bounds.bottom);
var radius=new OpenLayers.Feature.Vector(radiusGeometry);
var resize=(this.mode&OpenLayers.Control.ModifyFeature.RESIZE);
var rotate=(this.mode&OpenLayers.Control.ModifyFeature.ROTATE);
radiusGeometry.move=function(x,y){
OpenLayers.Geometry.Point.prototype.move.call(this,x,y);
var dx1=this.x-originGeometry.x;
var dy1=this.y-originGeometry.y;
var dx0=dx1-x;var dy0=dy1-y;
if(rotate){
var a0=Math.atan2(dy0,dx0);
var a1=Math.atan2(dy1,dx1);
var angle=a1-a0;angle*=180/Math.PI;geometry.rotate(angle,originGeometry);
}
if(resize){
var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));
var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));
geometry.resize(l1/l0,originGeometry);
}
};
this.radiusHandle=radius;
this.feature.layer.addFeatures([this.radiusHandle],{silent:true});
},
setMap:function(map){
this.selectControl.setMap(map);
this.dragControl.setMap(map);
OpenLayers.Control.prototype.setMap.apply(this,arguments);
},
CLASS_NAME:"OpenLayers.Control.MultipleLayersModifyFeature"
});
OpenLayers.Control.MultipleLayersDragFeature = OpenLayers.Class(OpenLayers.Control, {
geometryTypes: null,
onStart: function(feature, pixel) {},
onDrag: function(feature, pixel) {},
onComplete: function(feature, pixel) {},
layer: null,
feature: null,
dragCallbacks: {},
featureCallbacks: {},
lastPixel: null,
initialize: function(layer, options) {
OpenLayers.Control.prototype.initialize.apply(this, [options]);
this.layer = layer;
this.handlers = {
drag: new OpenLayers.Handler.Drag(
this, OpenLayers.Util.extend({
down: this.downFeature,
move: this.moveFeature,
up: this.upFeature,
out: this.cancel,
done: this.doneDragging
}, this.dragCallbacks)
),
feature: new OpenLayers.Handler.Feature(
this, this.layer, OpenLayers.Util.extend({
over: this.overFeature,
out: this.outFeature
}, this.featureCallbacks),
{geometryTypes: this.geometryTypes}
)
};
},
destroy: function() {
this.layer = null;
OpenLayers.Control.prototype.destroy.apply(this, []);
},
activate: function(layer) {
if (layer != this.layer) {
this.layer = layer;
this.handlers.feature.deactivate();
delete this.handlers.feature;
this.handlers.feature = new OpenLayers.Handler.Feature(
this, this.layer, OpenLayers.Util.extend({
over: this.overFeature,
out: this.outFeature
}, this.featureCallbacks),
{geometryTypes: this.geometryTypes}
);
}
return (this.handlers.feature.activate() &&
OpenLayers.Control.prototype.activate.apply(this, arguments));
},
deactivate: function() {
// the return from the handlers is unimportant in this case
this.handlers.drag.deactivate();
this.handlers.feature.deactivate();
this.feature = null;
this.dragging = false;
this.lastPixel = null;
return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
},
overFeature: function(feature) {
if(!this.handlers.drag.dragging) {
this.feature = feature;
this.handlers.drag.activate();
this.over = true;
// TBD replace with CSS classes
this.map.div.style.cursor = "move";
} else {
if(this.feature.id == feature.id) {
this.over = true;
} else {
this.over = false;
}
}
},
downFeature: function(pixel) {
this.lastPixel = pixel;
this.onStart(this.feature, pixel);
},
moveFeature: function(pixel) {
var res = this.map.getResolution();
this.feature.geometry.move(res * (pixel.x - this.lastPixel.x),
res * (this.lastPixel.y - pixel.y));
this.layer.drawFeature(this.feature);
this.lastPixel = pixel;
this.onDrag(this.feature, pixel);
},
upFeature: function(pixel) {
if(!this.over) {
this.handlers.drag.deactivate();
this.feature = null;
// TBD replace with CSS classes
this.map.div.style.cursor = "default";
} else {
// the drag handler itself resetted the cursor, so
// set it back to "move" here
this.map.div.style.cursor = "move";
}
},
doneDragging: function(pixel) {
this.onComplete(this.feature, pixel);
},
outFeature: function(feature) {
if(!this.handlers.drag.dragging) {
this.over = false;
this.handlers.drag.deactivate();
// TBD replace with CSS classes
this.map.div.style.cursor = "default";
this.feature = null;
} else {
if(this.feature.id == feature.id) {
this.over = false;
}
}
},
cancel: function() {
this.handlers.drag.deactivate();
this.over = false;
},
setMap: function(map) {
this.handlers.drag.setMap(map);
this.handlers.feature.setMap(map);
OpenLayers.Control.prototype.setMap.apply(this, arguments);
},
CLASS_NAME: "OpenLayers.Control.MultipleLayersDragFeature"
});
More information about the Dev
mailing list