1

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

2 Answers 2

2

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.

2
  • 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. Aug 4, 2015 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, 2015 at 15:09
0
var drawPolygon =  new OpenLayers.Control.DrawFeature(layer, 
OpenLayers.Handler.Polygon, 
{
  handlerOptions: {
     holeModifier: 'element',
  }
});

This should work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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