Openlayers labels overlapping - openlayers-3

I have a map with several markers that all have a label representing data at that marker point. When these markers overlap, the labels are always on top of all markers. I would like only the label for the top marker being shown. If two markers overlap right now, the label for the bottom marker still shows above the top marker. Does anyone know how to solve this problem in openlayers 3?

You can use the zIndex style property to stick labels to the marker. When working with a layer style function, the layer definition could look like this:
var style = new ol.style.Style({
text: new ol.style.Text({
text: '',
// ...
}),
image: new ol.style.Icon({
// ...
})
});
var styles = [style];
var index = 0;
var vectorLayer = new ol.layer.Vector({
style: function(feature, resolution) {
style.getText().setText(feature.get('name'));
style.setZIndex(index);
index = (index == Number.MAX_VALUE) ? 0 : index + 1;
return styles;
}
});

Related

can openlayers 3 render the animated marker using gif

I wanna ask how to make the marker show animated gif picture like openlayers 2 do...it can show the animated marker..what I want is show animated gif marker not make a marker move..it is possible or not?
style = {
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
anchor: anchor,
opacity: 1,
src: 'https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif',
scale: 1,
};
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ (style))
});
var iconFeature = new ol.Feature({
position: data.coordinate,
geometry: new ol.geom.Point([0,0]),
});
iconFeature.setStyle(iconStyle);
How to make https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif displayed animated as a gif in a map? is it possible or not create animated features in openlayers 3..I don't find any article with contain this solving...thanks
Yes there is a way do it but is a bit tricky so I am not sure whether it fit to your needs.
You need to add a marker instead and use css to style the marker.
check this
your html with the dom element
<div id="map" class="map"></div>
<div id="marker" title="Marker"></div>
your js here
var layer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [layer],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
// the position of your marker
var pos = ol.proj.fromLonLat([23.3725, 35.208889]);
var marker = new ol.Overlay({
position: pos,
positioning: 'center-center',
element: document.getElementById('marker'),
stopEvent: false
});
map.addOverlay(marker);
and your css here
#marker {
width: 365px;
height: 360px;
background: url("https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif") no-repeat scroll 0% 0% transparent;
}
and a fiddle here with the dancing banana (nice gif though :)))) )
This can definitely be done with a feature or layer style, with the help of a gif decoder that extracts the frames from the gif and controls an animation. Using gifler, the relevant code could look something like this:
const gifUrl = "./data/kgrtehja_DancingBannana.gif";
const gif = gifler(gifUrl);
gif.frames(
document.createElement("canvas"),
(ctx, frame) => {
if (!iconFeature.getStyle()) {
iconFeature.setStyle(
new Style({
image: new Icon({
img: ctx.canvas,
imgSize: [frame.width, frame.height]
})
})
);
}
ctx.clearRect(0, 0, frame.width, frame.height);
ctx.drawImage(frame.buffer, frame.x, frame.y);
map.render();
},
true
);
The above code sets an icon style with the animated gif on an existing feature. The feature is stored in a variable iconFeature.
See https://codesandbox.io/s/beautiful-fire-cdrou?file=/main.js for a working example.
An alternative is to use two png images. An effect similar to a gif image can be obtained if you apply two different styles to the same layer using the setStyle () method with a setInterval () function. Ej:
Style1 = {
...
src: '../image1.png',
...
};
Style2 = {
...
src: '../image2.png',
...
};
iconFeature.setStyle(Style1);
then
var n = 0; // global
function changeStyleEvery (){
if (n == 0){
n = 1;
iconFeature.setStyle(Style1);
}else{
n = 0;
iconFeature.setStyle(Style2);
};
};
function applyInterval (){
setInterval(function(){changeStyleEvery(); }, 500);
};

Restrict labeling to one label for MultiPolygon features

Default labeling in OpenLayers 3.10.1 labels each part of a MultiPolygon. I want to know if it is possible to label only the first polygon in the MultiPolygon.
You can use a separate style for the label with a geometry function, which returns a single point for the label position.
var styles = [
// Style for the label
new ol.style.Style({
text: new ol.style.Text({..}),
geometry: function(feature) {
// expecting a MultiPolygon here
var interiorPoints = feature.getGeometry().getInteriorPoints();
return interiorPoints.getPoint(0);
}
}),
// Style for the polygons
new ol.style.Style({
stroke: new ol.style.Stroke({...}),
fill: new ol.style.Fill({...})
})
];
http://jsfiddle.net/p0acpbtg/2/

Is it possible to set different colors to each segment of a LineString without meeting a huge performance hit?

My openlayers 3 application draws several LineString features on the map (from a few dozen up to 2000-3000).
When setting different colors for each segment of the LineStrings, I meet a huge performance hit (starting from just a few LineStrings on the map). The zoom and pan become completely unresponsive making my aplication not usable in this form.
Since I don't want to set a new geometry for each segment (but only change its color), I imagine there must be a more performance effective way of achieving this ?
Here's my code :
var styleFunction = function(feature, resolution) {
var i = 0, geometry = feature.getGeometry();
geometry.forEachSegment(function (start, end) {
color = colors[i];
styles.push(new ol.style.Style({
geometry: new ol.geom.LineString([start, end]),
fill: new ol.style.Fill({
color: color
}),
stroke: new ol.style.Stroke({
color: color,
width: 2
})
}));
i++;
});
return styles;
}
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: styleFunction
});
There are a few things that you can try to optimize:
Cache fill and stroke style
var fillStyles = colors.map(function(color, i) {
return new ol.style.Fill({
color: color
})
});
var strokeStyles = colors.map(function(color, i) {
return new ol.style.Stroke({
color: color,
width: 2
})
});
Cache the style for each feature
vectorSource.forEach(function(feature, i) {
var geometry = feature.getGeometry();
var styles = [];
var i = 0;
geometry.forEachSegment(function (start, end) {
styles.push(new ol.style.Style({
geometry: new ol.geom.LineString([start, end]),
fill: fillStyles[i],
stroke: strokeStyles[i]
}));
i++;
});
feature.setStyle(styles);
});
Disable that the rendering is updated during animations and interactions
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
updateWhileAnimating: false,
updateWhileInteracting: false
});
See ol.layer.Vector.
If all this doesn't help, you might also want to take a look at ol.source.ImageVector(example).
Since we could not solve the problem, even with tsauerwein's recommendations, this feature was put to the fridge for a while. Now we got back to it with fresh ideas and actually found a "solution".
Something that I made not clear in the question is that segments of a LineString are colored according to a property of their starting point. Several consecutive segments may thus share the same color if the value of this property doesn't change between them.
The idea is to avoid creating a new style for each and every segment but rather to create a new style only when necessary (when the color changes) :
let i = 0,
color = '#FE2EF7', //pink. should not be displayed
previousColor = '#FE2EF7',
lineString,
lastCoordinate = geometry.getLastCoordinate();
geometry.forEachSegment(((start, end) => {
color = this.getColorFromProperty(LinePoints[i].myProperty);
//First segment
if (lineString == null) {
lineString = new ol.geom.LineString([start, end]);
} else {
//Color changes: push the current segment and start a new one
if (color !== previousColor) {
styles.push(new ol.style.Style({
geometry: lineString,
fill: new ol.style.Fill({
color: previousColor
}),
stroke: new ol.style.Stroke({
color: previousColor,
width: 2
})
}));
lineString = new ol.geom.LineString([start, end]);
} else {
//Color is same: continue the current segment
lineString.appendCoordinate(end);
}
//Last segment
if (end[0] === lastCoordinate[0] && end[1] === lastCoordinate[1]) {
styles.push(new ol.style.Style({
geometry: lineString,
fill: new ol.style.Fill({
color: color
}),
stroke: new ol.style.Stroke({
color: color,
width: 2
})
}));
}
}
previousColor = color;
i++;
}

Re sizing the box based on open layers 3 map zoom

I am new to open layer 3 api's, I have a query : I have marked some locations and custom info window , which opens up on click of these markers. Please find fiddle here
var map = new ol.Map({
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([78, 21]),
zoom: 2
}),
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({
layer: 'osm'
})
})]
});
Is it possible do re-size the boxes when map is zommed in and out using mouse wheel. I plan to have many more cities marked , and boxes to be drawn on click of each marker and these boxes should be opened by default, so it would cover whole map . Can I change box size depending upon zoom level.
And also which layer to set to have map without any detailed information like airports , roads etc . I want map to have basic minimalist layer ,with country boundaries and city names only.
Thanks
You can listen to the view change:resolution event and make the boxes bigger using the zoom level. Here's an example:
var view = new ol.View({
center: ol.proj.fromLonLat([78, 21])
});
var parentZoom = null;
view.on('change:resolution', function() {
var zoom = view.getZoom();
if (parentZoom !== null) {
$('#zoom').text([
'Parent zoom:',
parentZoom,
', Current zoom:',
zoom
].join(' '));
}
var width = 50 + (zoom * 10);
var height = 30 + (zoom * 10);
$('.mapDivs').width(width + 'px').height(height + 'px');
parentZoom = zoom;
}, this);
view.setZoom(2);
See it live on JSFiddle (your example updated with the above code): http://jsfiddle.net/pe7hyr0x/15/

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.

Resources