Project

General

Profile

1
/*
2
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
3
$Id: FeatureSelectHandler.js 3842 2008-02-13 17:22:04Z ahocevar $
4
*/
5

    
6
// Ensure this object's dependancies are loaded.
7
mapbuilder.loadScript(baseDir+"/tool/ToolBase.js");
8
mapbuilder.loadScript(baseDir+"/util/openlayers/OpenLayers.js");
9

    
10
/**
11
 * Manages mouseover and clicks on vector features in the map.
12
 * This tool works with models that are linked to a OL vector layer,
13
 * using eg. the GmlRendererOL widget. Models have to fire the
14
 * 'gmlRendererLayer' event, which will activate the tool for the
15
 * layer.
16
 * This tool also fires "mouseoverFeature" and "mouseoutFeature"
17
 * events, setting the fid of the feature below the mouse cursor
18
 * as param of the model.
19
 * @constructor
20
 * @base ToolBase
21
 * @author Andreas Hocevar andreas.hocevarATgmail.com
22
 * @param toolNode The tool node from the config XML file.
23
 * @param model The model containing this tool.
24
 */
25
function FeatureSelectHandler(toolNode, model) {
26
  ToolBase.apply(this, new Array(toolNode, model));
27
   
28
  /**
29
   * Map for this FeatureSelectHandler. We keep a reference
30
   * to the map we created the control for, to prevent ourselves
31
   * from removing the control from a map that does not exist
32
   * anymore.
33
   */
34
  this.map = null;
35
  
36
  this.sourceModels = new Array();
37
  
38
  /**
39
   * Tool Initialisation - Step 1 of 3.
40
   * This is called when the config finished loading, so we know
41
   * our context (targetModel).
42
   * @param objRef This object
43
   */
44
  this.configInit = function(objRef) {
45
    objRef.targetModel.addListener('loadModel', objRef.contextInit, objRef);
46
  }
47
  this.model.addListener('init', this.configInit, this)
48
  
49
  this.clear = function(objRef) {
50
    if (objRef.control) {
51
      objRef.map = null;
52
      objRef.control.destroy();
53
      objRef.control = null;
54
    }
55
  }
56
  this.model.addListener("newModel", this.clear, this);
57

    
58
  /**
59
   * Tool Initialisation - Step 2 of 3.
60
   * This is called when the context model finished loading, so we
61
   * know that we have a map available.
62
   * @param objRef This object
63
   */
64
  this.contextInit = function(objRef) {
65
    objRef.targetModel.addListener("newModel", objRef.clear, objRef);
66
    objRef.model.addListener('gmlRendererLayer', objRef.init, objRef);
67
    // Check carefully if we have to init manually. This is the case when
68
    // the gmlRendererLayer is rendered, but does not know about the
69
    // FeatureSelectHandler yet.
70
    if (objRef.targetModel.map && objRef.model.getParam('gmlRendererLayer') && !objRef.control) {
71
      objRef.init(objRef);
72
    }
73
  }
74
  
75
  /**
76
   * Tool Initialisation - Step 3 of 3.
77
   * Turns on feature select when the gmlRendererLayer event is fired.
78
   * @param objRef reference to this object.
79
   * @return {OpenLayers.Control} class of the OL control.
80
   */
81
  this.init = function(objRef) {
82
    // get the source models
83
    var sourceModel;
84
    // if we have mergeModels, take sourceModels from there
85
    if (objRef.model.mergeModels) {
86
      objRef.sourceModels = objRef.model.mergeModels;
87
    } else {
88
      // if we hava a plain model, just use it
89
      objRef.sourceModels.push(objRef.model);
90
    } 
91
    for (var i=0; i<objRef.sourceModels.length; i++) {
92
      objRef.sourceModels[i].addListener('highlightFeature', objRef.highlight, objRef);
93
      objRef.sourceModels[i].addListener('dehighlightFeature', objRef.dehighlight, objRef);
94
    }
95
    
96
    // init the control
97
    var layer = objRef.model.getParam('gmlRendererLayer');
98
    if (objRef.map == objRef.targetModel.map &&
99
        objRef.control && !layer) {
100
      //objRef.control.deactivate();
101
      objRef.map.removeControl(objRef.control);
102
      objRef.control.destroy();
103
      objRef.control = null;
104
    } else if (layer) {
105
      if (!objRef.control) {
106
        objRef.control = new OpenLayers.Control.SelectFeature(layer, {
107
          hover: true,
108
          onSelect: objRef.onSelect,
109
          onUnselect: objRef.onUnselect,
110
          mbFeatureSelectHandler: objRef,
111
          select: function(feature) {
112
            feature.mbFeatureSelectHandler = this.mbFeatureSelectHandler;
113
            if (feature.mbSelectStyle) {
114
              this.selectStyle = feature.mbSelectStyle.createSymbolizer ?
115
                  feature.mbSelectStyle.createSymbolizer(feature) :
116
                  feature.mbSelectStyle;
117
            }
118
            OpenLayers.Control.SelectFeature.prototype.select.apply(this, arguments);
119
          }
120
        });
121
        objRef.map = objRef.targetModel.map;
122
        objRef.map.addControl(objRef.control);
123
      }
124
      objRef.control.activate();
125
    }
126
  }
127
  
128
  /**
129
   * extension for the OpenLayers.Feature.Vector.destroy method.
130
   * Will be applied to features touched by this tool.
131
   */
132
  var destroyFeature = function() {
133
    var featureSelectHandler = this.mbFeatureSelectHandler;
134
    if (this.layer.events && featureSelectHandler) {
135
      this.layer.events.unregister('mousedown', this, featureSelectHandler.onClick);
136
      this.layer.events.unregister('mousemove', this, featureSelectHandler.onHover);
137
    }
138
    this.mbFeatureSelectHandler = null;
139
    OpenLayers.Feature.Vector.prototype.destroy.apply(this, arguments);
140
  }
141

    
142
  /**
143
   * This method is triggered when the mouse is over a vector
144
   * feature. It registers priority events mousedown and
145
   * mousemove, which will call this widget's onClick/onHover
146
   * method in the context of a feature. This way we address
147
   * two problems with the OpenLayers SelectFeature control:<pre>
148
   *      - for the info popup, we need the screen coordinates
149
   *        which we do not get from the handler directly.
150
   *      - when the active tool changes, something in the
151
   *        priority of OL event handlers changes, so the
152
   *        click event on the feature gets lost. By registering
153
   *        our priority handler and calling Event.stop() in
154
   *        the target method, we make sure that our event is
155
   *        handled and no other event handlers are triggered.
156
   * </pre>
157
   * @param feature OpenLayers feature
158
   */
159
  this.onSelect = function(feature) {
160
    if (!feature) return;
161
    var objRef = this.mbFeatureSelectHandler;
162
    for (var i=0; i<objRef.sourceModels.length; i++) {
163
      objRef.sourceModels[i].setParam("mouseoverFeature", feature.fid);
164
    }
165
    // check if onSelect was triggered by a mouse event. If not, do not register for
166
    // mousedown and mousemove events. This is the case when selection was externally
167
    // triggered by the highlightFeature event
168
    if (feature.layer.events && !feature.mbNoMouseEvent) {
169
      feature.destroy = destroyFeature;
170
      feature.layer.events.registerPriority('mousedown', feature, objRef.onClick);
171
      feature.layer.events.registerPriority('mousemove', feature, objRef.onHover);
172
    } else {
173
      feature.mbNoMouseEvent = null;
174
    }
175
  }
176
  
177
  /**
178
   * This method is triggered when the mouse is moving out
179
   * of a vector feature. It removes the event handler we
180
   * registered in this widget's onSelect method.
181
   * @param feature OpenLayers feature
182
   */
183
  this.onUnselect = function(feature) {
184
    if (!feature) return;
185
    var objRef = this.mbFeatureSelectHandler || feature.mbFeatureSelectHandler;
186
    for (var i=0; i<objRef.sourceModels.length; i++) {
187
      objRef.sourceModels[i].setParam("mouseoutFeature", feature.fid);
188
    }
189
    objRef.model.setParam("olFeatureOut", feature);
190
    if (feature.layer.events) {
191
      feature.layer.events.unregister('mousedown', feature, objRef.onClick);
192
    }
193
  }
194
  
195
  /**
196
   * This method is triggered when a user clicks on a feature.
197
   * It is called by OpenLayers event handling in the context
198
   * of a feature. This means that 'this' in this method refers
199
   * to an {OpenLayers.Feature}. Widgets listening to the
200
   * olFeatureSelect have access to the event, because setParam
201
   * is used to set the reference to the event.
202
   * @param evt OpenLayers event
203
   */
204
  this.onClick = function(evt) {
205
    // pass the feature to the event object
206
    evt.feature = this;
207
    var objRef = this.mbFeatureSelectHandler;
208
    objRef.model.setParam("olFeatureSelect", evt);
209
    OpenLayers.Event.stop(evt);
210
  }
211
  
212
  /**
213
   * This method is triggered when the mouse is over a feature.
214
   * It is called by OpenLayers event handling in the context
215
   * of a feature. This means that 'this' in this method refers
216
   * to an {OpenLayers.Feature}. Widgets listening to the
217
   * olFeatureHover have access to the event, because setParam
218
   * is used to set the reference to the event.
219
   * @param evt OpenLayers event
220
   */
221
  this.onHover = function(evt) {
222
    var objRef = this.mbFeatureSelectHandler;
223
    if (this.layer && this.layer.events) {
224
      // unregister the mousemove event, because we already know that
225
      // the mouse moved and we can then proceed to our hover popup.
226
      this.layer.events.unregister('mousemove', this, objRef.onHover);
227
    }
228
    evt.feature = this;
229
    objRef.model.setParam("olFeatureHover", evt);
230
  }
231

    
232
  /**
233
   * Highlights the specified feature. This method is usually
234
   * triggered by setting the 'highlightFeature' param to the
235
   * fid of a feature to be highlighted.
236
   * @param objRef reference to this tool object
237
   * @param fid GML feature id of the feature to highlight. If
238
   * not specified, this is taken from the highlightFeature
239
   * model param.
240
   */
241
  this.highlight = function(objRef, fid) {
242
    var model, feature;
243
    var layer = objRef.model.getParam('gmlRendererLayer');
244
    for (var i=0; i<objRef.sourceModels.length; i++) {
245
      model = objRef.sourceModels[i]
246
      if (!layer) return;
247
      if (!fid) {
248
        fid = model.getParam('highlightFeature');
249
      }
250
      feature = layer.getFeatureByFid(fid);
251
      if (feature && !feature.mbHidden) {
252
        // add a tag to the feature to indicate that it was not selected by mouse action
253
        feature.mbNoMouseEvent = true;
254
        objRef.control.select(feature);
255
      }
256
    }
257
  }
258
  
259
  /**
260
   * Dehighlights the specified feature. This method is usually
261
   * triggered by setting the 'dehighlightFeature' param to the
262
   * fid of a feature to be highlighted.
263
   * @param objRef reference to this tool object
264
   * @param fid GML feature id of the feature to highlight. If
265
   * not specified, this is taken from the dehighlightFeature
266
   * model param.
267
   */
268
  this.dehighlight = function(objRef, fid) {
269
    var model, feature;
270
    var layer = objRef.model.getParam('gmlRendererLayer');
271
    for (var i=0; i<objRef.sourceModels.length; i++) {
272
      model = objRef.sourceModels[i];
273
      if (!layer) return;
274
      if (!fid) {
275
        fid = objRef.model.getParam('dehighlightFeature');
276
      }
277
      feature = layer.getFeatureByFid(fid);
278
      if (feature && !feature.mbHidden) {
279
        objRef.control.unselect(feature);
280
      }
281
    }
282
  }
283
  
284
}
(6-6/15)