0

I want to draw some paths using OpenLayers.

Add new Layer

    var mLayer = new OpenLayers.Layer.Vector("New Layer", {
        styleMap : new OpenLayers.StyleMap(markerStyle)
    });
    var editPanel = new DOU.EditingToolbar(mLayer);
    map.addLayer(mLayer);
    map.addControl(editPanel);

enter image description here

To draw Path, I use Path Control. But when I change control (Example, I click to Move Control or Point Control, all Markers (which you can see in the picture) will be removed.

Do you have any suggestion?

My Code:

DOU.HandlerPath = OpenLayers.Class(DOU.HandlerPoint, {

    /**
     * Property: line
     * {<OpenLayers.Feature.Vector>}
     */
    line : null,

    /**
     * APIProperty: maxVertices
     * {Number} The maximum number of vertices which can be drawn by this
     * handler. When the number of vertices reaches maxVertices, the
     * geometry is automatically finalized. Default is null.
     */
    maxVertices : null,

    /**
     * Property: doubleTouchTolerance
     * {Number} Maximum number of pixels between two touches for
     * the gesture to be considered a "finalize feature" action.
     * Default is 20.
     */
    doubleTouchTolerance : 20,

    /**
     * Property: freehand
     * {Boolean} In freehand mode, the handler starts the path on mouse down,
     * adds a point for every mouse move, and finishes the path on mouse up.
     * Outside of freehand mode, a point is added to the path on every mouse
     * click and double-click finishes the path.
     */
    freehand : false,

    /**
     * Property: freehandToggle
     * {String} If set, freehandToggle is checked on mouse events and will set
     * the freehand mode to the opposite of this.freehand. To disallow
     * toggling between freehand and non-freehand mode, set freehandToggle to
     * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and 'altKey'.
     */
    freehandToggle : 'shiftKey',

    /**
     * Property: timerId
     * {Integer} The timer used to test the double touch.
     */
    timerId : null,

    /**
     * Property: redoStack
     * {Array} Stack containing points removed with <undo>.
     */
    redoStack : null,

    /**
     * Constructor: OpenLayers.Handler.Path
     * Create a new path hander
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     * functions. Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     * handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created. Callback called with
     * the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     * geometry and the sketch feature.
     * point - Called as each point is added. Receives the new point geometry.
     * done - Called when the point drawing is finished. The callback will
     * recieve a single argument, the linestring geometry.
     * cancel - Called when the handler is deactivated while drawing. The
     * cancel callback will receive a geometry.
     */

    /**
     * Method: createFeature
     * Add temporary geometries
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
     * feature.
     */
    createFeature : function(pixel) {
        var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
        var geometry = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
        // this.point = new OpenLayers.Feature.Vector(geometry);
        this.point = new OpenLayers.Feature.Vector(geometry, {}, DOU.PointStyle);
        this.line = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([this.point.geometry]), {}, DOU.LineStyle);

        this.callback("create", [this.point.geometry, this.getSketch(), this.ps]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.line, this.point], {
            // silent : true
        });
    },

    /**
     * Method: destroyFeature
     * Destroy temporary geometries
     *
     * Parameters:
     * force - {Boolean} Destroy even if persist is true.
     */
    destroyFeature : function(force) {
        //DOU.HandlerPoint.prototype.destroyFeature.call(this, force);
        this.line = null;
    },

    /**
     * Method: destroyPersistedFeature
     * Destroy the persisted feature.
     */
    destroyPersistedFeature : function() {
        var layer = this.layer;
        if (layer && layer.features.length > 2) {
            // this.layer.features[0].destroy();
        }
    },

    /**
     * Method: removePoint
     * Destroy the temporary point.
     */
    /*
    removePoint : function() {
    if (this.point) {
    this.layer.removeFeatures([this.point]);
    }
    },*/

    /**
     * Method: addPoint
     * Add point to geometry. Send the point index to override
     * the behavior of LinearRing that disregards adding duplicate points.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
     */
    addPoint : function(pixel) {
        //this.layer.removeFeatures([this.point]);
        var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
        this.point = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat));

        this.line.geometry.addComponent(this.point.geometry, this.line.geometry.components.length);

        this.layer.addFeatures([this.point]);

        this.callback("point", [this.point.geometry, this.getGeometry()]);
        this.callback("modify", [this.point.geometry, this.getSketch()]);
        this.drawFeature();
        delete this.redoStack;
    },

    /**
     * Method: insertXY
     * Insert a point in the current sketch given x & y coordinates. The new
     * point is inserted immediately before the most recently drawn point.
     *
     * Parameters:
     * x - {Number} The x-coordinate of the point.
     * y - {Number} The y-coordinate of the point.
     */
    insertXY : function(x, y) {
        this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x, y), this.getCurrentPointIndex());
        this.drawFeature();
        delete this.redoStack;
    },

    /**
     * Method: insertDeltaXY
     * Insert a point given offsets from the previously inserted point.
     *
     * Parameters:
     * dx - {Number} The x-coordinate offset of the point.
     * dy - {Number} The y-coordinate offset of the point.
     */
    insertDeltaXY : function(dx, dy) {
        var previousIndex = this.getCurrentPointIndex() - 1;
        var p0 = this.line.geometry.components[previousIndex];
        if (p0 && !isNaN(p0.x) && !isNaN(p0.y)) {
            this.insertXY(p0.x + dx, p0.y + dy);
        }
    },

    /**
     * Method: insertDirectionLength
     * Insert a point in the current sketch given a direction and a length.
     *
     * Parameters:
     * direction - {Number} Degrees clockwise from the positive x-axis.
     * length - {Number} Distance from the previously drawn point.
     */
    insertDirectionLength : function(direction, length) {
        direction *= Math.PI / 180;
        var dx = length * Math.cos(direction);
        var dy = length * Math.sin(direction);
        this.insertDeltaXY(dx, dy);
    },

    /**
     * Method: insertDeflectionLength
     * Insert a point in the current sketch given a deflection and a length.
     * The deflection should be degrees clockwise from the previously
     * digitized segment.
     *
     * Parameters:
     * deflection - {Number} Degrees clockwise from the previous segment.
     * length - {Number} Distance from the previously drawn point.
     */
    insertDeflectionLength : function(deflection, length) {
        var previousIndex = this.getCurrentPointIndex() - 1;
        if (previousIndex > 0) {
            var p1 = this.line.geometry.components[previousIndex];
            var p0 = this.line.geometry.components[previousIndex - 1];
            var theta = Math.atan2(p1.y - p0.y, p1.x - p0.x);
            this.insertDirectionLength((theta * 180 / Math.PI) + deflection, length);
        }
    },

    /**
     * Method: getCurrentPointIndex
     *
     * Returns:
     * {Number} The index of the most recently drawn point.
     */
    getCurrentPointIndex : function() {
        return this.line.geometry.components.length - 1;
    },

    /**
     * Method: undo
     * Remove the most recently added point in the sketch geometry.
     *
     * Returns:
     * {Boolean} A point was removed.
     */
    undo : function() {
        var geometry = this.line.geometry;
        var components = geometry.components;
        var index = this.getCurrentPointIndex() - 1;
        var target = components[index];
        var undone = geometry.removeComponent(target);
        if (undone) {
            // On touch devices, set the current ("mouse location") point to
            // match the last digitized point.
            if (this.touch && index > 0) {
                components = geometry.components;
                // safety
                var lastpt = components[index - 1];
                var curptidx = this.getCurrentPointIndex();
                var curpt = components[curptidx];
                curpt.x = lastpt.x;
                curpt.y = lastpt.y;
            }
            if (!this.redoStack) {
                this.redoStack = [];
            }
            this.redoStack.push(target);
            this.drawFeature();
        }
        return undone;
    },

    /**
     * Method: redo
     * Reinsert the most recently removed point resulting from an <undo> call.
     * The undo stack is deleted whenever a point is added by other means.
     *
     * Returns:
     * {Boolean} A point was added.
     */
    redo : function() {
        var target = this.redoStack && this.redoStack.pop();
        if (target) {
            this.line.geometry.addComponent(target, this.getCurrentPointIndex());
            this.drawFeature();
        }
        return !!target;
    },

    /**
     * Method: freehandMode
     * Determine whether to behave in freehand mode or not.
     *
     * Returns:
     * {Boolean}
     */
    freehandMode : function(evt) {
        return (this.freehandToggle && evt[this.freehandToggle]) ? !this.freehand : this.freehand;
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given the new point
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest
     * point.
     * drawing - {Boolean} Indicate if we're currently drawing.
     */
    modifyFeature : function(pixel, drawing) {
        if (!this.line) {
            this.createFeature(pixel);
        }
        var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
        this.point.geometry.x = lonlat.lon;
        this.point.geometry.y = lonlat.lat;

        this.callback("modify", [this.point.geometry, this.getSketch(), drawing]);
        this.point.geometry.clearBounds();
        this.drawFeature();
    },

    /**
     * Method: drawFeature
     * Render geometries on the temporary layer.
     */
    drawFeature : function() {
        this.layer.drawFeature(this.line, this.style);
        this.layer.drawFeature(this.point, this.style);
    },

    /**
     * Method: getSketch
     * Return the sketch feature.
     *
     * Returns:
     * {<OpenLayers.Feature.Vector>}
     */
    getSketch : function() {
        return this.line;
    },

    /**
     * Method: getGeometry
     * Return the sketch geometry. If <multi> is true, this will return
     * a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.LineString>}
     */
    getGeometry : function() {
        var geometry = this.line && this.line.geometry;
        if (geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiLineString([geometry]);
        }
        return geometry;
    },

    /**
     * method: touchstart
     * handle touchstart.
     *
     * parameters:
     * evt - {event} the browser event
     *
     * returns:
     * {boolean} allow event propagation
     */
    touchstart : function(evt) {
        if (this.timerId && this.passesTolerance(this.lastTouchPx, evt.xy, this.doubleTouchTolerance)) {
            // double-tap, finalize the geometry
            this.finishGeometry();
            window.clearTimeout(this.timerId);
            this.timerId = null;
            return false;
        } else {
            if (this.timerId) {
                window.clearTimeout(this.timerId);
                this.timerId = null;
            }
            this.timerId = window.setTimeout(OpenLayers.Function.bind(function() {
                this.timerId = null;
            }, this), 300);
            return DOU.HandlerPoint.prototype.touchstart.call(this, evt);
        }
    },

    /**
     * Method: down
     * Handle mousedown and touchstart. Add a new point to the geometry and
     * render it. Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    down : function(evt) {
        var stopDown = this.stopDown;
        if (this.freehandMode(evt)) {
            stopDown = true;
            if (this.touch) {
                this.modifyFeature(evt.xy, !!this.lastUp);
                OpenLayers.Event.stop(evt);
            }
        }
        if (!this.touch && (!this.lastDown || !this.passesTolerance(this.lastDown, evt.xy, this.pixelTolerance))) {
            this.modifyFeature(evt.xy, !!this.lastUp);
        }
        this.mouseDown = true;
        this.lastDown = evt.xy;
        this.stoppedDown = stopDown;
        return !stopDown;
    },

    /**
     * Method: move
     * Handle mousemove and touchmove. Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    move : function(evt) {
        if (this.stoppedDown && this.freehandMode(evt)) {
            if (this.persist) {
                this.destroyPersistedFeature();
            }
            if (this.maxVertices && this.line && this.line.geometry.components.length === this.maxVertices) {
                //this.removePoint();
                this.finalize();
            } else {
                this.addPoint(evt.xy);
            }
            return false;
        }
        if (!this.touch && (!this.mouseDown || this.stoppedDown)) {
            this.modifyFeature(evt.xy, !!this.lastUp);
        }
        return true;
    },

    /**
     * Method: up
     * Handle mouseup and touchend. Send the latest point in the geometry to
     * the control. Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    up : function(evt) {
        if (this.mouseDown && (!this.lastUp || !this.lastUp.equals(evt.xy))) {
            if (this.stoppedDown && this.freehandMode(evt)) {
                if (this.persist) {
                    this.destroyPersistedFeature();
                }
                //this.removePoint();
                this.finalize();
            } else {
                if (this.passesTolerance(this.lastDown, evt.xy, this.pixelTolerance)) {
                    if (this.touch) {
                        this.modifyFeature(evt.xy);
                    }
                    if (this.lastUp == null && this.persist) {
                        this.destroyPersistedFeature();
                    }
                    this.addPoint(evt.xy);
                    this.lastUp = evt.xy;
                    if (this.line.geometry.components.length === this.maxVertices + 1) {
                        this.finishGeometry();
                    }
                }
            }
        }
        this.stoppedDown = this.stopDown;
        this.mouseDown = false;
        return !this.stopUp;
    },

    /**
     * APIMethod: finishGeometry
     * Finish the geometry and send it back to the control.
     */
    finishGeometry : function() {
        var index = this.line.geometry.components.length - 1;
        this.line.geometry.removeComponent(this.line.geometry.components[index]);
        //this.removePoint();
        this.finalize();
    },

    /**
     * Method: dblclick
     * Handle double-clicks.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    dblclick : function(evt) {
        if (!this.freehandMode(evt)) {
            this.finishGeometry();
        }
        return false;
    },

    CLASS_NAME : "OpenLayers.Handler.Path"
});

DOU.EditingToolbar = OpenLayers.Class(OpenLayers.Control.Panel, {

    /**
     * APIProperty: citeCompliant
     * {Boolean} If set to true, coordinates of features drawn in a map extent
     * crossing the date line won't exceed the world bounds. Default is false.
     */
    citeCompliant : false,

    /**
     * Constructor: OpenLayers.Control.EditingToolbar
     * Create an editing toolbar for a given layer.
     *
     * Parameters:
     * layer - {<OpenLayers.Layer.Vector>}
     * options - {Object}
     */
    initialize : function(layer, options) {
        OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);

        this.addControls([new OpenLayers.Control.Navigation()]);
        var controls = [new OpenLayers.Control.DrawFeature(layer, DOU.HandlerPoint, {
            displayClass : 'olControlDrawFeaturePoint',
            handlerOptions : {
                citeCompliant : this.citeCompliant
            }
        }), new OpenLayers.Control.DrawFeature(layer, DOU.HandlerPath, {
            displayClass : 'olControlDrawFeaturePath',
            handlerOptions : {
                citeCompliant : this.citeCompliant
            }
        })];
        this.addControls(controls);
    },

    /**
     * Method: draw
     * calls the default draw, and then activates mouse defaults.
     *
     * Returns:
     * {DOMElement}
     */
    draw : function() {
        var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments);
        if (this.defaultControl === null) {
            this.defaultControl = this.controls[0];
        }
        return div;
    },

    CLASS_NAME : "OpenLayers.Control.EditingToolbar"
});
  • Does it work without the this.point.geometry.clearBounds(); call? – BradHards Mar 17 '14 at 4:45
  • :D No. I try to remove this.point.geometry.clearBounds(); But, nothing changes. :( – Luc Mar 17 '14 at 8:00
1

I solved this problem. I want to share you the way to resolve if you get the same problem.

In this time. I added the lines and the points in the same layer.

 this.layer.addFeatures([this.point]);
 this.layer.addFeatures([this.line]);

No no. May be it is not available. So when I try to add points to other layer. It works fine.

 this.layer.addFeatures([this.point]);
 this.otherLayer.addFeatures([this.line]);
| improve this answer | |
0

The code seems to work (we need DOU.HandlerPoint). Are you adding the vector layer to the map?

map = new OpenLayers.Map(mapOptions);
var osm = new OpenLayers.Layer.OSM('OSM', ["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],{transitionEffect: 'resize'});   
map.addLayer(osm);

var lyr =  new OpenLayers.Layer.Vector("Line Layer");
var control = new DOU.EditingToolbar(lyr);
map.addLayer(lyr); // Be sure to add the vector layer to the map
map.addControl(lyr);
| improve this answer | |
  • Yes. I added layer to map. :( – Luc Mar 17 '14 at 16:13
  • Could you post a full example? It works for me :) – Tommaso Mar 17 '14 at 17:06
  • I update my question – Luc Mar 18 '14 at 1:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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