From 72dd05e63a7c44e854616de08b45d1827a2ad04b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=A4rtwig?= Date: Wed, 11 Feb 2015 14:46:29 +0100 Subject: [PATCH] Created control 'ContextMenu' for displaying controls in a panel appearing next to the selected features --- Makefile | 3 +- lib/Editor.js | 19 +++- lib/Editor/Control/ContextMenu.js | 145 ++++++++++++++++++++++++++++++ lib/loader.js | 1 + 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 lib/Editor/Control/ContextMenu.js diff --git a/Makefile b/Makefile index 46e3e64..679afa2 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ minified: --js 'lib/Editor/Control/UndoRedo.js' \ --js 'lib/Editor/Control/CADTools.js' \ --js 'lib/Editor/Control/ParallelDrawing.js' \ + --js 'lib/Editor/Control/ContextMenu.js' \ --js 'lib/Editor/Lang/ca.js' \ --js 'lib/Editor/Lang/de.js' \ --js 'lib/Editor/Lang/en.js' \ @@ -50,4 +51,4 @@ pack_distribution: minified zip --recurse-paths $(DISTRIBUTION_NAME).zip examples/ lib/ tests/ theme/ documentation.md features.md license.txt Makefile README.md ole.min.js rm -f $(DISTRIBUTION_NAME).tar.gz - tar -pczf $(DISTRIBUTION_NAME).tar.gz examples/ lib/ tests/ theme/ documentation.md features.md license.txt Makefile README.md ole.min.js \ No newline at end of file + tar -pczf $(DISTRIBUTION_NAME).tar.gz examples/ lib/ tests/ theme/ documentation.md features.md license.txt Makefile README.md ole.min.js diff --git a/lib/Editor.js b/lib/Editor.js index 9f95cb7..802ae07 100644 --- a/lib/Editor.js +++ b/lib/Editor.js @@ -81,7 +81,7 @@ OpenLayers.Editor = OpenLayers.Class({ editorControls: ['CleanFeature', 'DeleteFeature', 'DeleteAllFeatures', 'Dialog', 'DrawHole', 'DrawRegular', 'DrawPolygon', 'DrawPath', 'DrawPoint', 'DrawText', 'EditorPanel', 'ImportFeature', 'MergeFeature', 'SnappingSettings', 'SplitFeature', 'CADTools', - 'TransformFeature'], + 'TransformFeature', 'ContextMenu'], /** * Geometry types available for editing @@ -427,7 +427,6 @@ OpenLayers.Editor = OpenLayers.Class({ OpenLayers.Util.extend({}, this.UploadFeature) )); break; - } // Save instance in editor's controls mapping @@ -456,6 +455,22 @@ OpenLayers.Editor = OpenLayers.Class({ * @return {OpenLayers.Editor.Control.EditorPanel} Widget to display editing tools */ createEditorPanel: function (controls) { + + // remove controls from context menu + if (this.controls['ContextMenu']) { + var ctrls = this.controls['ContextMenu'].contextMenuControls || []; + var i = ctrls.length; + while (i--) { + var pos = controls.indexOf(this.controls[ctrls[i]]); + if (~pos) { + controls.splice(pos, 1); + } + } + + controls.splice(controls.indexOf(this.controls['ContextMenu']), 1); + } + + var editorPanel = new OpenLayers.Editor.Control.EditorPanel(this); editorPanel.addControls(controls); return editorPanel; diff --git a/lib/Editor/Control/ContextMenu.js b/lib/Editor/Control/ContextMenu.js new file mode 100644 index 0000000..559d9f5 --- /dev/null +++ b/lib/Editor/Control/ContextMenu.js @@ -0,0 +1,145 @@ +/** + * @copyright 2015 geOps + * @license https://github.com/geops/ole/blob/master/license.txt + * @link https://github.com/geops/ole + */ + +/** + * Class: OpenLayers.Editor.Control.ContextMenu + * The ContextMenu contains editor controls + * and is opened on feature selection + * + * Inherits from: + * - + * + * @constructor + * @param {OpenLayers.Layer} The editor layer + * @param {Object=} options + */ +OpenLayers.Editor.Control.ContextMenu = OpenLayers.Class(OpenLayers.Control.Panel, { + + /** + * {Number} Type of the control + */ + type: OpenLayers.Control.TYPE_BUTTON, + + /** + * {Number} Distance (in pixel) of the context menu to the bbox + * of the selected features + */ + menuBufferDistance: 10, + + /** + * {Array} Contains list of controls appearing on context menu + */ + contextMenuControls: ['CleanFeature', 'DeleteFeature', 'DrawHole', + 'MergeFeature', 'SplitFeature', 'TransformFeature'], + + /** + * Constructor OpenLayers.Editor.Control.ContextMenu + * + * Parameters: + * @param {OpenLayers.Layer} The editor layer + * @param {Object} options + */ + initialize: function (layer, options) { + layer.events.register('featureselected', this, this.openContextMenu); + layer.events.register('featureunselected', this, this.closeContextMenu); + layer.map.events.register('move', this, this.updatePosition); + + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); + + layer.map.addControl(this); + }, + + /** + * Move all context menu controls from editor panel + * to this panel + */ + addContextMenuControls: function() { + var controls = []; + for (var i = 0; i < this.contextMenuControls.length; i++) { + var controlName = this.contextMenuControls[i]; + var control = this.map.editor.controls[controlName]; + if (control) { + controls.push(control); + } + } + + this.addControls(controls); + }, + + /** + * Open the context menu + */ + openContextMenu: function() { + this.div.style.display = ''; + this.addContextMenuControls(); + this.activate(); + this.updatePosition(); + + for (var i = 0; i < this.controls.length; i++) { + OpenLayers.Element.removeClass(this.controls[i].panel_div, + 'oleControlDisabled'); + } + }, + + /** + * Close the context menu + */ + closeContextMenu: function() { + if (!this.map.editor.editLayer.selectedFeatures.length) { + this.div.style.display = 'none'; + this.deactivate(); + } + }, + + /** + * Place the context menu on the point on the selected features' + * bounding box with the smallest distance to the map center. + */ + updatePosition: function() { + var selFeatures = this.map.editor.editLayer.selectedFeatures; + + if (!selFeatures.length) { + return; + } + + var bounds = new OpenLayers.Bounds(); + var mapCenter = this.map.getExtent().getCenterLonLat(); + mapCenter = new OpenLayers.Geometry.Point( + mapCenter.lon, mapCenter.lat); + + for (var i = 0; i < (selFeatures || []).length; i++) { + bounds.extend(selFeatures[i].geometry.getBounds()); + } + + var dist = bounds.toGeometry().distanceTo(mapCenter, + {'details': true}) || {'x0': bounds.left, 'y0': bounds.top}; + + var menuPosition = this.map.getPixelFromLonLat( + new OpenLayers.LonLat(dist.x0, dist.y0)); + + this.div.style.right = 'initial'; + this.div.style.left = menuPosition.x + 'px'; + this.div.style.top = menuPosition.y + 'px'; + + if (dist.y0 === bounds.top) { + this.div.style.top = parseInt(this.div.style.top) - + this.menuBufferDistance - this.div.clientHeight + 'px'; + } else if (dist.y0 === bounds.bottom) { + this.div.style.top = parseInt(this.div.style.top) + + this.menuBufferDistance + 'px'; + } + + if (dist.x0 === bounds.left) { + this.div.style.left = parseInt(this.div.style.left) - + this.menuBufferDistance - this.div.clientWidth + 'px'; + } else if (dist.x0 === bounds.right) { + this.div.style.left = parseInt(this.div.style.left) + + this.menuBufferDistance + 'px'; + } + }, + + CLASS_NAME: 'oleContextMenu OpenLayers.Editor.Control.EditorPanel' +}); diff --git a/lib/loader.js b/lib/loader.js index c446365..9ce29bb 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -8,6 +8,7 @@ 'compat.js', 'Editor.js', 'Editor/Control/CleanFeature.js', + 'Editor/Control/ContextMenu.js', 'Editor/Control/DragFeature.js', 'Editor/Control/DeleteFeature.js', 'Editor/Control/DeleteAllFeatures.js',