Get box boundaries from select box in OpenLayers - javascript

I have an OpenLayers map and I want users to be able to draw a box by dragging their mouse (similar to this example here, select the "select feature (0 features selected)" option first) and obtain the boundaries of the drawn box.
I can manage to draw the box using smth like below, however it won't work when there are no features in the map or no features selected, and that will certainly be the case.
new OpenLayers.Control.SelectFeature(this._layers.osm, {
multiple: true,
box: true,
hover: false,
toggleKey: 'ctrlKey',
multipleKey: 'shiftKey',
onBeforeSelect: function() {
console.log(arguments);
}
})
Is there an easy way to accomplish this in OpenLayers or should I do the heavy lifting myself by tracking mouse drags and drawing/removing polygons accordingly?
Thanks.

Try to use "boxselectionend" event of SelectFeature control (requires 2.12)
But this event not returns boundaries or the selection made, only returns a layers array.
Another option is to create the Handler.Box externally, that is what I do in some cases as:
var mySelectFeature = OpenLayers.Control.SelectFeature(...);
var myHandlerBox = new OpenLayers.Handler.Box(
mySelectFeature, {
done: function(bounds) {
OpenLayers.Control.SelectFeature.prototype.selectBox.apply(
mySelectFeature, arguments);
... your code ...
}
},
{}
);

Related

How can I dismiss a HERE Maps context menu programmatically?

I have a HERE Maps map displayed on a simple webpage with a multiselect dropdown and a couple of buttons. I'm using the contextmenu event to show a context menu on right-click, like so:
var map = new H.Map(
document.getElementById('mapContainer'),
maptypes.raster.normal.map,
{
zoom: 12,
center: { lat: -33.81, lng: 150.78 },
pixelRatio: window.devicePixelRatio || 1,
engineType: H.map.render.RenderEngine.EngineType.P2D
}
);
...
// an H.map.Polygon object we prepared earlier
polygonObject.addEventListener("contextmenu", handleContextMenu)
...
function handleContextMenu(evt) {
// Don't do anything if the map itself is right-clicked/long-pressed
if (evt.target === map) {
return;
}
if (evt.target instanceof H.map.Polygon) {
// Polygon-specific context menu items
evt.items.push(new H.util.ContextItem({ label: "ABC123" }));
evt.items.push(H.util.ContextItem.SEPARATOR);
evt.items.push(new H.util.ContextItem({ label: "Do something", callback: function () { doSomething(evt) } }));
}
}
This works fine, displays a context menu when a polygon object is right-clicked, and dismisses itself if somewhere else on the map is tapped. However, the context menu doesn't dismiss if the user clicks or interacts with another element on the page outside the map.
I wasn't able to find any documentation on how to achieve this behaviour, and the example that HERE Maps uses also doesn't dismiss the context menu if somewhere outside the map is clicked. Is there any way to dismiss the context menu on a map, either programmatically or automatically if another page element is interacted with?
It's a little bit hacky, but you can manually remove the context menu from the DOM by finding a div with the h_context_menu class in the page, and removing it. This may have some unintended side effects with the UI class, but seems to work OK from my brief testing.
Using JQuery:
$("div.h_context_menu").remove()
Using ES6:
document.querySelector("div.h_context_menu").remove()
Using vanilla JavaScript (compatible with Internet Explorer):
var el = document.querySelector("div.h_context_menu");
el.parentNode.removeChild(el);

Creating "Tools" in FabricJS?

I am working on a simple editor where you can move text, pictures, and pretty much anything around. It's nothing too complicated, however I am having an issue choosing between using PaperJS and FabricJS - The main reason being the ability to natively transform items (rotate, scale, etc.).
Even though I love PaperJS, I am really considering moving to FabricJS. I create tools for PaperJS like this:
function shapeTool(options) {
this.tool = new Tool();
var options = $.extend({
shape: "circle",
}, options);
this.tool.onMouseUp = function(event) { ... }
...
...
this.tool.activate();
return tool;
}
This is probably the worst way to create them, but for me it's easy to throw all these functions in a file and init my tools: var tool = new shapeTool(options);
Since I will possibly be moving to Fabric, what is the easiest way to make modular tools. In which I can swap between them? (i.e. I have a toolbar and when i click a button my tool changed so i can freedraw, insert images, etc)
Clarification: When I mean a tool, I am talking about a tool in PaperJS. IN Paper, we are able to swap the canvas's active tool. The tool would handle the current mouseDown, KeyDown, etc. events for the canvas. I could write different tools for things like inserting shapes and images, and write one for freedrawing. I could then set the active tool to either one. This would allow me to swap between freedraw and inserting shapes.
Thanks,
Hunter M.
In FabricJS you interact with the behaviour of mouse with events.
Cavas fires:
mouse:down
mouse:move
mouse:up
mouse:over
mouse:out
You register events with ON and OFF:
canvas.on('mouse:down', handler);
You have just on predefined state that is drawingMode true or false
canvas.isDrawingMode = true;
And free drawing starts.
When not drawing the mouse down and up or move can be customized by a property you add to canvs.
canvas.myState = 'addStamps';
Then in your handler:
handler(e) {
switch (canvas.myState) {
case 'deleteItems':
e.target && canvas.remove(e.target);
break;
case 'addStamps':
canvas.add(new fabric.Image('stamp.jpg'));
break;
}
}
You have to do same for mouse:up or mosue:move if you need interaction other than clicks.
This is one of the many ways you can obtain a similar effect.

Selecting feature clusters in OpenLayers 3

At the moment I have my map set up to cluster icons upon zooming out. I want to disable the ability to select clusters but allow the user to select individual markers if they zoom in. Preferably, clicking on a cluster should select each individual feature in the cluster (in their correct locations). My select code is like so:
var selectClick = new ol.interaction.Select({
condition: ol.events.condition.click,
style: selectedMarkerStyle,
addCondition: function(mapBrowserEvent){
var features = null;
map.forEachFeatureAtPixel(mapBrowserEvent.pixel, function (feature_, layer) {
features = feature_.values_.features;
});
if(features !== null && features.length > 1){
return false;
}
return true;
}
});
map.addInteraction(selectClick);
I tried to make the addCondition check if multiple features are located at the point and then stop the event however it doesn't seem to be working. At the moment clicking on a cluster selects one of the features in the cluster, in the location of the cluster, rather than the features correct location. Is there anyway to fix this?
Thanks

OpenLayers Click on selected Feature triggering function

I am using OpenLayers to draw point features on a map with a cluster strategy.
strategy = new OpenLayers.Strategy.Cluster();
clusters = new OpenLayers.Layer.Vector("Clusters", {
strategies: [strategy],
styleMap: new OpenLayers.StyleMap({
"default": style,
"select": {
fillColor: "#ff0000",
strokeColor: "#ffbbbb"
}
})
});
[.......]
clusters.addFeatures(features);
I'm also using a SelectFeature to select the point features on my map.
select = new OpenLayers.Control.SelectFeature(
clusters, {
clickout: false,
toggle: false,
hover: false
}
);
map.addControl(select);
select.activate();
clusters.events.on({"featureselected": clickPoint});
When the user selects a clustered Feature a popup appears with a list of containing features to select. When he selects one of these the popup closes and the clustered feature remains selected.
Now comes the problem. I want to be able click on the clustered feature so the popup appears again. The only thing I'm able to do is to set toggle:true but then the feature gets unselected.
Is there a way to trigger an event when the user clicks on a selected Feature?
Thx in advance,
illy
To solve this problem I overwrite unselectAll as:
mySelectControl.unselectAll = function(options) {
OpenLayers.Control.SelectFeature.prototype.unselectAll.apply(
mySelectControl, arguments);
if (options && options.except) {
var myReselecteFeature = options.except;
... your code to show the popup of myReselecteFeature ...
}
};
You may be interested to look at this example:
http://jorix.github.com/OL-FeaturePopups/examples/feature-popups.html
It is a control that does this you do and a little more. For example keeps the selection after zooming using clusters.
NOTE: The default behavior is not what you are looking for but can be customized.
You could also unSelect your feature when the feature is selected. For me it was the shortest way to achieve for the click event for the feature. Also set the toggle flag to true to fire unselect event in case of clicks.
var pdfFeatureSelector = new OpenLayers.Control.SelectFeature(pdfLayer,{
clickout: true,
multiple: true,
toggle: true,
autoActivate: true,
onSelect: function(){
OpenLayers.Control.SelectFeature.prototype.unselectAll.apply(
pdfFeatureSelector);//unselect the feature when it is selected
}
});

OpenLayers SelectFeature control with hover delay?

Using OpenLayers, I have a OpenLayers.Control.SelectFeature installed on a layer, with the hover option set to true. When creating the layer I call
<layer>.events.register("featureselected",...)
and
<layer>.events.register("featureunselected",...)
to register functions that create and destroy a popup. This all works fine. Now I want to add a small delay before the popup is created in order to avoid the popup flickering that currently occurs when moving the mouse across multiple features. However, I can't seem to figure out how to do this. I did find the OpenLayers.Handler.Hover handler, which has a delay option, but I don't know how to combine that with the SelectFeature control (if I even can).
I think this post has some valuable info, which I'm about to verify. Some answers down, someone talks about the flickering.
edit: In case you are making your own labels, I noticed the effect is less when you raise the labelOutlineWidth . It seems that only the letters of the label count as 'hover' and not the whole PointRadius radius. When you make the label outline too big, the label looks like a fly that hit a windscreen though (not a square but it follows the label contours, the letters more specifically).
update: apparently this is why when you hover a text label , check this out: pointer events properties. set this attribute (pointerEvents: ) in your OpenLayers.Style and try value 'all' and the others. It sure makes a difference for me.
I bind my feature selections a little different, here's a quick (untested) example that should get you what you need.
var timer,
delay = 500, //delay in ms
hover = new OpenLayers.Control.SelectFeature( <layer> , {
hover: true,
onSelect: function (feature) {
// setup a timer to run select function
timer = window.setTimeout(function () {
// your select code
}, delay);
},
onUnselect: function () {
// first cancel the pending timer (no side effects)
window.clearTimeout(timer);
// your unselect code
}
});
<map>.addControl(hover);
hover.activate();

Categories