Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I would like to create a button "draw a hole" taht uses by default the holeModifier functionality but the user dont need to press the cttrlBtn.

The "standard" way I guess, would be to create a way of create holes in OpenLayers would be something like this:

var drawPolygon = new OpenLayers.Control.DrawFeature(ftthLayer, 
                     OpenLayers.Handler.Polygon,{
                        handlerOptions: { holeModifier: "ctrlKey"} };

By this way the user needs to press the ctrlKey to draw a hole, or else a new polygon is created. Is it possible to make the control DrawFeature always be in "holeModifier" mode?

I have tried setting the property drawingHole= true on the handler (OpenLayers.Handler.Polygon) that's connected to DrawFeature control , but that doesn't seem to help.

I know there are different ways to solve hole creation, but the ones I have seen havn't solved so that the user see you are drawing a hole. Like the way it's working when you use the holeModifier.

Happy for any input

Br Mike

share|improve this question

1 Answer 1

This works:

OpenLayers.Handler.PolygonHolePuncherHandler = (function PolygonHolePuncherHandler_module( OpenLayers, undefined )
{
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=//
/**
* Example: 
var drawControl = new OpenLayers.Control.DrawFeature(
    olVectorLayer,
    OpenLayers.Handler.PolygonHolePuncherHandler,
    {
        'handlerOptions':
        {
            'events':
            {
                'beforepunchinghole':function( evt )
                {return( document.getElementById( 'is_punching' ).checked );}
            },
            'holeModifier':'altKey'
        }
    }
);
olMap.addControl( drawControl );
drawControl.activate();
*/
var PolygonHolePuncherHandler = OpenLayers.Class( OpenLayers.Handler.Polygon, 
{
    /**
    * Constructor: OpenLayers.Handler.PolygonHolePuncherHandler
    * Create a Polygon Handler.
    *
    * Parameters:
    * control - {<OpenLayers.Control>} The control that owns this handler
    * eventListeners - {Object} An object with a properties whose values are
    *   functions.  Events described below.
    * options - {Object} An optional object with properties to be set on the
    *   handler
    *
    * Named events:
    * beforepunchinghole - Called to determine whether hole punching should be performed.  
    *   The callback will receive (a copy of) the polygon geometry.
    */
    'CLASS_NAME':'OpenLayers.Handler.PolygonHolePuncherHandler',
    'addPoint':function PolygonHolePuncherHandler_addPoint( olPixel )
    {
        var before_punching_hole = this.events.triggerEvent( 'beforepunchinghole' );
        // If the event handler returns "truthy" or has nothing to say.
        if( !!before_punching_hole || before_punching_hole === undefined )
        {
            if( !!before_punching_hole )
            {
                this.evt = OpenLayers.Util.extend({}, this.evt );
                this.evt[ this.holeModifier ] = is_punching;
            }
            // else 'before_punching_hole' is undefined, assume nothing.
        }
        // else 'before_punching_hole' is false, do not override.
        // Forward the call to the parent, OpenLayers.Handler.Polygon.
        return( OpenLayers.Handler.Polygon.prototype.addPoint.apply( this, arguments ));
    },
    'destroy':function PolygonHolePuncherHandler_destroy()
    {
        if( !!this.events )
        {
            if( !!this.eventListeners )
            {this.events.un( this.eventListeners );}
            this.events.destroy();
            this.events = null;
        }
        this.eventListeners = null;
        this.options = null;
        return( OpenLayers.Handler.Polygon.prototype['destroy'].apply( this, arguments ));
    },
    'initialize':function PolygonHolePuncherHandler_initialize( olControl, callbacks, options )
    {
        // backup original options
        this.options = OpenLayers.Util.extend({}, options );
        // now override default options 
        OpenLayers.Util.extend( this, options );
        this.events = new OpenLayers.Events( this );
        // register event listeners
        if( this.eventListeners instanceof Object )
        {this.events.on( this.eventListeners );}
        return( OpenLayers.Handler.Polygon.prototype['initialize'].apply( this, arguments ));
    },
});
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=//
return( PolygonHolePuncherHandler );
})( OpenLayers );

The "magic" is that this handler intercepts the 'addPoint' calls, gives the developer the opportunity to override drawing a hole (does not disable drawing holes), conditionally overrides the event's 'holeModifier' property ('altKey', 'ctrlKey', or 'shiftKey') by replacing it, then forwards the calls to the default Polygon handler. So, in the 'beforepunchinghole' handler, check the state of a checkbox (or some other form of toggle) to indicate whether a hole is being drawn.

The 'destroy' and 'initialize' overrides are used to manage the 'events' property configured with the 'eventListeners' option.

More work needs to be done to find an inexpensive way of checking whether the point intersects a feature. If it's not intersecting one, don't trigger the 'beforepunchinghole' event.

share|improve this answer
    
Could you put in a few words of why this might work please. The code does look nice, well formatted and commented... it would be good though to explain where the magic is. –  Michael Miles-Stimson Aug 4 at 5:48
    
I added comments to the methodology. I'm not sure whether using OpenLayers callbacks or events is better. I'm leaning toward events being better because it eliminates a magic-string member property. I will change it to use events if asked. –  MarkMYoung Aug 4 at 15:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.