Open Layers 3 Icon overlap tearing - openlayers-3

I have a vector layer with a lot of close together data, each rendered by an icon. When rendered in Open Layers 3 using icons of any type/design I often get tearing of elements trying to get through others, I'm sure many people using Open Layers will have seen this happen.
Is there a way of solving this issue?
My code is fairly standard:
var styleCache2 = {};
var WFS_layer_Dangerous_Bends = new ol.layer.Vector({
source : new ol.source.GeoJSON({
projection : 'EPSG:3857',
url : "Vector_Data/A_Vector_Data_Set.geojson"
}),
style : function(feature, resolution) {
if (!styleCache2[path]) {
styleCache2[path] = [new ol.style.Style({
fill : new ol.style.Fill({
color : 'rgba(255, 255, 255, 0.1)'
}),
stroke : new ol.style.Stroke({
color : '#319FD3',
width : 1
}),
image: new ol.style.Icon(({
anchor: [x_anchor, y_anchor],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
src: path
}))
}),
zIndex : 1
})];
}
return styleCache2[path];
}
});
/*Creating the map object linked to the map selector/div in the HTML */
map_object = new ol.Map({
target: 'map',
controls: controls_list,
interactions: interactions_list,
overlays: [overlay],
layers: [OSM_raster, WFS_layer_Dangerous_Bends],
view: view
});
Obviously overlay, controls_list, interactions_list and the OSM_raster are defined somewhere too, but I don't think they're relevant to the question so I haven't included them.
I tried to capture an example, it's quite difficult because its intermittent, this shows about 5 icons overlapping normally, but a couple in the middle are tearing through each other:

Related

OL3 / Geoserver: Vector tile labels gets cropped

I am trying to label vector tile point features but they always gets cropped at the tile border. I have tried (among many other things) using the renderBuffer option with no success.
I am using OL 3.19 and the vector tiles are served with Geoserver 2.10RC1 and I get the same errors in my production environment as well as editing an Boundless example (http://suite.opengeo.org/docs/latest/dataadmin/vectortiles/index.html).
I think maybe the tiles are served correctly from Geoserver and that Openlayers somehow render and then slices the tiles before presentation but I am kind of stuck on this.
Any ideas?
Screenshot of the way it looks
And the code snippet:
<script>
var style_simple = new ol.style.Style({
fill: new ol.style.Fill({
color: '#ADD8E6'
}),
stroke: new ol.style.Stroke({
color: '#880000',
width: 1
}),
text: new ol.style.Text({
text:'LOREMIPSUM'})
});
function simpleStyle(feature) {
return style_simple;
}
var map = new ol.Map({
target: 'map',
view: new ol.View({
center: [0,0],
zoom: 4
}),
layers: [new ol.layer.VectorTile({
renderBuffer:50, //doesn't matter
style:simpleStyle,
source: new ol.source.VectorTile({
tilePixelRatio: 1,
tileGrid: ol.tilegrid.createXYZ({maxZoom: 19}),
format: new ol.format.MVT(),
url: 'http://localhost:8080/geoserver/gwc/service/tms/1.0.0/testlayer#EPSG%3A3857#pbf/{z}/{x}/{-y}.pbf'
})
})]
});
</script>
I have the same problem with ol.layer.VectorTile and text labels.
All labels are sliced on the tile boundaries.
Full example: https://jsfiddle.net/rn3qc4ca/
I asked the openlayers developers for help: https://github.com/openlayers/ol3/issues/6275
-> This is not a bug in openlayers. The mapbox tiles really repeat the label points in neighbored tiles. If you use very big fonts the label will still be cropped.
My (unimplemented) idea is to place all labels into a separate ol.layer.Vector layer. As this type of layer is not sliced into tiles it is always printed completely.

ol.style.Circle with ol.layer.Vector throws error

I draw features on a map (WKT POINTs). Now I would like to give those points a radius. Before I even add Features and the layer to the map I do the following:
var src = new ol.source.Vector();
var layer = new ol.layer.Vector({
source: src,
style: new ol.style.Circle({
radius: 30
})
});
This throws the following error:
AssertionError: Assertion failed: obj geometry must be an ol.style.Style instance
at goog.asserts.DEFAULT_ERROR_HANDLER (http://localhost:33464/app/lib/openLayers/ol-debug.js:4330:52)
at goog.asserts.doAssertFailure_ (http://localhost:33464/app/lib/openLayers/ol-debug.js:4365:3)
at goog.asserts.assertInstanceof (http://localhost:33464/app/lib/openLayers/ol-debug.js:4575:5)
at ol.style.createStyleFunction (http://localhost:33464/app/lib/openLayers/ol-debug.js:56402:7)
at ol.layer.Vector.prototype.setStyle (http://localhost:33464/app/lib/openLayers/ol-debug.js:58228:3)
at ol.layer.Vector (http://localhost:33464/app/lib/openLayers/ol-debug.js:58115:3)
If instead I add the same style to the "new ol.layer.Tile" I'm using to display the OpenStreetMap (ol.source.OSM) in the background everything works perfect:
map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
style: new ol.style.Circle({
radius: 30
})
})
]
});
I don't really understand that. I guess it has something to do with ol.style.Circle extending ol.style.Image (which doesn't sound like something for a vector layer - rather the raster layer "Tile"). But if I add the style to the Tile-Layer, why are the features on the vector-Layer rendering with this style?
My questions:
What is the correct way of doing this?
Is there a "style-Inheritance" going on?
style is not a valid option of the ol.layer.Tile object, thus it is simply ignored. See its documentation: http://openlayers.org/en/v3.10.1/apidoc/ol.layer.Tile.html
The style definition defined in the ol.layer.Vector has to be either of the following:
a ol.style.Style object
an array of ol.style.Style objects
a style function, i.e. ol.style.StyleFunction.
So, in order for your example to work, you could define a style that looks like this:
var src = new ol.source.Vector();
var layer = new ol.layer.Vector({
source: src,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 30,
fill: new ol.style.Fill({color: 'red'})
})
})
});
This example demonstrates custom style: http://openlayers.org/en/v3.10.1/examples/custom-interactions.html
See also the API documentation: http://openlayers.org/en/v3.10.1/apidoc/ol.layer.Vector.html

Selectable Points of vector layer have an offset

I've got a vector layer with a GeoJSON source, consisting of Points and a LineString. When I click on a point I want to open a popup with additional information.
Here's some code:
var style = {
'Point': [new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: 'rgb(255,0,0)'
}),
radius: 5,
stroke: new ol.style.Stroke({
color: '#000000',
width: 1
}),
})
})],
'LineString': [new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ff0000',
width: 3
})
})],
'MultiLineString': [new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#0000ff',
width: 3
})
})]
};
var map = new ol.Map({
target: 'map-ol-canvas',
interactions: ol.interaction.defaults({mouseWheelZoom: false}),
layers: [new ol.layer.Tile({ source: new ol.source.OSM() })],
view: new ol.View({
zoom: 8,
maxZoom: 16
})
});
map.getView().fit(extent, map.getSize());
var trackSource = new ol.source.Vector({
url: '/test.geojson',
format: new ol.format.GeoJSON()
});
var track = new ol.layer.Vector({
source: trackSource,
style: function(feature, resolution) {
return style[feature.getGeometry().getType()];
}
});
map.addLayer(track);
var select = new ol.interaction.Select({
filter: function (feature, layer) {
return feature.getGeometry().getType() === 'Point';
}
});
map.addInteraction(select);
// When user clicks on a waypoint, show a tooltip.
function onMouseClick(browserEvent) {
var coordinate = browserEvent.coordinate;
var pixel = map.getPixelFromCoordinate(coordinate);
map.forEachFeatureAtPixel(pixel, function(feature) {
if (feature.getGeometry().getType() === 'Point') {
console.log(feature.get('date'));
}
});
}
map.on('click', onMouseClick);
The problem:
When I click directly on a point nothing happens. When I click a couple of pixels below and a bit right or left (depends on zoom level!), the point gets selected and the console.log is triggered.
I can fix this by using Firebox WebDeveloper Addon and activating "Disable all styles".
However, when I manually remove all CSS one by one that behavior never goes away.
In the first place I thought this might be some inherited padding or margin, but currently I think the canvas shouldn't be affected by any CSS at all.
Any ideas about what could be wrong?
I'm experiencing the same issue. It appears to be linked to navigating to the page from a specific modal (I'm using ajax hash paging). The footer doesn't load and after I interact with the first feature on the map the following happens;
The map jumps and stretches/smears slightly
The footer shows up on my page
The vertical scroll bar appears
The issue doesn't seem to occur when i link from another page.
I have the same problem.Here are some advices may help you:
check the the size of map's container(may be a Div).
check the size of map(openlayers's map object).
compare that two size to confirm whether the two size are equal.
if not, you can use the map.setSize([width,height])to adjust the map's size.

where can i find a thorough description of implementing custom ol.style.Style in openlayers 3?

I've read through the source, and looked at the examples but haven't found the answer yet.
I need to style the image that appears on the modify overlay beneath the mouse cursor.
i'm using a custom style function to add midpoints and custom endpoints to the layer used by ol.interaction.Modify. ol.interaction.Modify is applying styling to a point near the mouse cursor to indicate that the feature can be modified. This is great except the cursor styling falls beneath the custom endpoints. i can't find a way to alter the z-index.
so, i'm answering my question for myself. i guess that's what makes the internet wonderful. i'm not a dog.
// we'd normally pass feature & resolution parameters to the function, but we're going to
// make this dynamic, so we'll return a style function for later use which will take those params.
DynamicStyleFunction = ( function( /* no feat/res yet!*/ ) {
/**
you really only get style are rendered upon simple geometries, not features. features are made of different geometry types, and styleFunctions are passed a feature that has its geometries rendered. in terms of styling vector geometries, you have only a few options. side note: if there's some feature you expect to see on the the map and it's not showing up, you probably haven't properly styled it. Or, maybe it hasn't been put it in a collection that is included in the source layer... which is a hiccup for a different day.
*/
// for any geometry that you want to be rendered, you'll want a style.
var styles = {};
var s = styles;
/**
an ol.layer.Vector or FeatureOverlay, renders those features in its source by applying Styles made of Strokes, Fills, and Images (made of strokes and fills) on top of the simple geometries which make up the features
Stroke styles get applied to ol.geom.GeometryType.LINE_STRING
MULTI_LINE_STRING can get different styling if you want
*/
var strokeLinesWhite = new ol.style.Stroke({
color: [255, 255, 255, 1], // white
width: 5,
})
var whiteLineStyle new ol.style.Style({
stroke: strokeLinesWhite
})
styles[ol.geom.GeometryType.LINE_STRING] = whiteLineStyle
/**
Polygon styles get applied to ol.geom.GeometryType.POLYGON
Polygons are gonna get filled. They also have Lines... so they can take stroke
*/
var fillPolygonBlue = new ol.style.Style({
fill: new ol.style.Fill({
color: [0, 153, 255, 1], // blue
})
})
var whiteOutlinedBluePolygon = new ol.style.Style({
stroke: strokeLinesWhite,
fill: fillPolygonBlue,
})
styles[ol.geom.GeometryType.POLYGON] = fillPolygonBlue
/**
Circle styles get applied to ol.geom.GeometryType.POINT
They're made with a radius and a fill, and the edge gets stroked...
*/
var smallRedCircleStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: '#FF0000', // red... but i had to look it up
})
})
})
var whiteBigCircleWithBlueBorderStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: '#FFFFFF' // i guessed it
})
}),
stroke: new.ol.style.Stroke({
color: '#0000FF', // blue
width: 5
})
})
// render all points as small red circles
styles[ol.geom.GeometryType.POINT] = smallRedCircleStyle
// if you pass an array as the style argument, every rendering of the feature will apply every defined style style rendered with the geometry as the argument. that can be a whole lot of rendering in a FeatureOverlay...
smallRedCircleStyle.setZIndex(Infinity)
whiteBigCircleWithBlueBorderStyle.setZIndex(Infinity -1) // that prob wouldn't work, but i hope it's instructive that you can tinker with styles
// so...
var bullseyePointStyle = [ smallRedCircleStyle, whiteBigCircleWithBlueBorderStyle ];
return function dynamicStyleFunction (feature, resolution){
// this is the actual function getting invoked on each function call
// do whatever you want with the feature/resolution.
if (Array.indexOf(feature.getKeys('thisIsOurBullseyeNode') > -1) {
return bullseyePointStyle
} else if (feature.getGeometryName('whiteBlueBox')){
return whiteOutlinedBluePolygon
} else {
return styles[feature.getGeometryName()]
}
}
})()
ol.interaction.Modify, ol.interaction.Select and ol.interaction.Draw take a style argument to change the look of the sketching features.

What's "an array of ol.style.Style" good for?

A style of an ol.layer.Vector can be set as ol.style.Style, a style function or an array of ol.style.Style. What's the array for and what does it do -- compared to just passing an ol.style.Style object?
I cannot find any information on this, neither in the official API docs nor in the tutorials.
If you look at the draw features example, when drawing lines, they are displayed in blue with a white border/outline.
These is achieved by styling the line twice, first with a large white line, then a thin blue line above.
There are 2 styles for the same geometry. It can’t be done with a single ol.style.Style, so to achieve this you need to pass an array of 2 styles: see the source for this.
Because I think this is still relevant and the edit queue is full for the approved answer, I'm posting this with the links updated and with code examples.
The most common way to see the array of styles in action is when drawing features since this is default style in Openlayers. For the line to appear blue with a white border it has to have two styles since it can't be done with a single Style. Openlayers does this by default like this:
styles['LineString'] = [
new Style({
stroke: new Stroke({
color: white,
width: width + 2,
}),
}),
new Style({
stroke: new Stroke({
color: blue,
width: width,
}),
}),
];
source
To expand on how usefull this feature could be you could check the custom polygons example. To have the vertices highlighted, they use two styles, one for the vertices and another for the polygon contour itself. Relevant piece of code:
const styles = [
new Style({
stroke: new Stroke({
color: 'blue',
width: 3,
}),
fill: new Fill({
color: 'rgba(0, 0, 255, 0.1)',
}),
}),
new Style({
image: new CircleStyle({
radius: 5,
fill: new Fill({
color: 'orange',
}),
}),
geometry: function (feature) {
// return the coordinates of the first ring of the polygon
const coordinates = feature.getGeometry().getCoordinates()[0];
return new MultiPoint(coordinates);
},
}),
];

Resources