Need to find a way to rotate a feature in openlayer3 while editing a feature.
Like in openlayer2 https://github.com/openlayers/openlayers/blob/master/examples/rotate-features.html
function rotateFeature(feature, angle, origin) {
feature.geometry.rotate(angle, origin);
feature.layer.drawFeature(feature);
}
Basically, all you have to do is to call the rotate function for you polygon, as shown in the code below:
var vectorSource = new ol.source.Vector({});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://localhost/map_cache.php?z={z}&x={x}&y={y}'
})
}),
new ol.layer.Vector({
source: vectorSource
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
var marker = new ol.geom.Polygon([[
ol.proj.transform([-16,-22], 'EPSG:4326', 'EPSG:3857'),
ol.proj.transform([-44,-55], 'EPSG:4326', 'EPSG:3857'),
ol.proj.transform([-88,75], 'EPSG:4326', 'EPSG:3857')
]]);
var featureMarker = new ol.Feature({
name: 'Marker',
geometry: marker,
});
vectorSource.addFeature(featureMarker);
//Here is the code for rotating:
marker.rotate(Math.PI / 2.0, ol.proj.transform([-16,-22], 'EPSG:4326', 'EPSG:3857'));
//////////////////////////////////////////////////
map.on('click', function(evt)
{
var lonlat = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326');
console.log(lonlat);
});
I have created an example to rotate a feature:
Gist with code
The rotate feature is built in and turned on by default. You can rotate your map by pressing alt + shift and moving your mouse on the map. A button should appear to revert back the rotation back to 0 degrees.
http://openlayers.org/en/v3.9.0/apidoc/ol.control.html
Related
I'm tring to get the coordinate of a location when I click on a marker. I can get latitude and longitude of a location but they aren't the same that I used to set them
For example if i use latitude:48.879882939225 longitude: 2.3558143608438 to set the marker for Paris, when I click on the same marker I receive latitude:49.00659123218202 longitude: 2.2758007269287077
I write this to set the map and its markers
let markers = getMarkers(data);
$('.content').html(
'<div id="map" class="map" style="height: 100%; width: 100%"></div>'
)
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([12.51, 41.89]),
zoom:6
})
});
map.on('singleclick', function(evt){
console.log(ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326'));
let lat = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')[0];
let lng = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')[1];
});
var features = [];
for (var i = 0; i < markers.length; i++) {
var item = markers[i];
var longitude = item.lng;
var latitude = item.lat;
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([longitude, latitude], 'EPSG:4326', 'EPSG:3857'))
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(({
anchor: [0.5, 1],
src: "http://cdn.mapmarker.io/api/v1/pin?text=P&size=50&hoffset=1"
}))
});
iconFeature.setStyle(iconStyle);
features.push(iconFeature);
}
var vectorSource = new ol.source.Vector({
features: features
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
How can I get the correct coordinate ?
At zoom level 6 your marker will be more than 0.1 degrees wide. To get the coordinates of the marker use something like
map.on('singleclick', function(evt){
let features = map.getFeaturesAtPixel(evt.pixel);
if (features.length > 0) {
let coordinate = features[0].getGeometry().getCoordinates();
console.log(ol.proj.transform(coordinate, 'EPSG:3857', 'EPSG:4326'));
let lat = ol.proj.transform(coordinate, 'EPSG:3857', 'EPSG:4326')[0];
let lng = ol.proj.transform(coordinate, 'EPSG:3857', 'EPSG:4326')[1];
}
});
I'm trying to open a popup in a map with markers, getting the markers points from a list where latitude and longitude are given, and they are plotted correctly in the map.
Following https://openlayers.org/en/latest/examples/popup.html I added the code for opening popup, and this is my code:
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
var overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
closer.onclick = function() {
overlay.setPosition(undefined);
closer.blur();
return false;
};
// create the map with the proper center
var map = new ol.Map({
controls: ol.control.defaults().extend(
[new ol.control.ScaleLine()]
),
view: new ol.View({
center: ol.proj.fromLonLat([center.long, center.lat]),
zoom: zoom
}),
overlays: [overlay],
layers: [new ol.layer.Tile(
{source: new ol.source.OSM()}
)
],
target: 'mapdiv',
keyboardEventTarget: document
}
);
// the style for the markers
var markerStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {module:ol/style/Icon~Options} */ ({
anchor: [0.5, 1],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
scale: 0.4,
src: 'img/ic_place_void_black_24dp_2x.png'
}))
});
for (i = 0; i < pointList.length; ++i) {
// add the marker
markersList[i] = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([pointList[i].long, pointList[i].lat])),
namesList: pointList[i].mediaNameList
});
// apply the style to the marker
markersList[i].setStyle(markerStyle);
}
// generate the markers vector
var markers = new ol.source.Vector({
features: markersList
});
// generate the markers layer
var markerVectorLayer = new ol.layer.Vector({
source: markers,
});
// add the markers layer to the map
map.addLayer(markerVectorLayer);
/**
* Add a click handler to the map to render the popup.
*/
map.on('singleclick', function(evt) {
var clickedPosition = ol.proj.toLonLat(evt.coordinate);
console.log(clickedPosition);;
overlay.setPosition(ol.proj.fromLonLat(clickedPosition));
});
Now I'm stuck with a unexplicable behaviour; whenever I click, the popup is shown about one screen south-east, whatever zoom level of the map.
The coordinates of clickedPosition (I'm seeing them in the console) are the correct coordinates where I clicked, but the popup is shown in a wrong point, with a shift which is always the same in pixels.
What am I missing?
You can refer overlay positioning for showing features in any world.
follow the link
I need to implement a measure tool with OpenLayers, and I would like to display distance on the segment, with a smart management of the scale (a mark on the segment each 10m, then each 50m, 100m, 1km, 5km, for example...), very much like the GoogleMaps "measure distance" tool.
Is there any library doing that ? What would be the good approach to implement it ?
In short: No, I don't know any lib or class that provides what you want out of the box.
Option 1: Customize ScaleLine
ScaleLine (see api docs) has the option to provide your own render function (see code). The default implementation just calculates the distance and shows it as {number} {scale} by calling the internal function updateElement_, which then updates the ScaleLine's innerHtml.
You could theoretically replace that method and set the innerHTML yourself. That approach might limit you to the development-variant of the library, because the production code is minified and those elements (innerElement_, element_) are not marked as api.
new ol.control.ScaleLine({
render: function(mapEvent) {
// do stuff
}
});
Option 2: Use the Draw Feature with customized LineString styles
so that might be too complicated and I suggest you go for the ol.interaction.Draw feature. The Measure Example shows us how one could draw stuff while the user is drawing a line. You can combine that with custom styles on a LineString.
// TODO split the uses drawn line into segments, like this mockup
const line = new ol.geom.LineString([
[20.0, 50.0],
[30.0, 47.0],
[40.0, 47.0],
[50.0, 47.0]
]);
line.transform('EPSG:4326', 'EPSG:3857');
const lineFeature = new ol.Feature(line);
const lineSource = new ol.source.Vector({
features: [lineFeature]
});
function segmentText(coord, coord2) {
const coord_t = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
let coordText = coord_t[1].toFixed(0) + '/' + coord_t[0].toFixed(0);
if(coord2) {
const length = ol.Sphere.getLength(new ol.geom.LineString([coord2, coord]));
const distance = (Math.round(length / 1000 * 100) / 100) + ' km';
coordText = coordText + '\n' + distance;
} else {
coordText = coordText + '\n0';
}
return new ol.style.Text({
text: coordText,
fill: new ol.style.Fill({
color: "#00f"
}),
offsetY: 25,
align: 'center',
scale: 1,
});
}
function styleFunction(feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring style
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ff0000',
width: 2
})
})
];
function createSegmentStyle(coord, coord2, rotation) {
return new ol.style.Style({
geometry: new ol.geom.Point(coord),
image: new ol.style.Icon({
src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAIAAADdv/LVAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAUSURBVBhXY1Da6MPEwMDAxMDAAAALMAEkQYjH8gAAAABJRU5ErkJggg==',
anchor: [0.75, 0.5],
rotateWithView: true,
rotation: -rotation,
scale: 4
}),
text: segmentText(coord, coord2)
})
};
const firstCoord = geometry.getFirstCoordinate();
geometry.forEachSegment(function (start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
if (firstCoord[0] === start[0] && firstCoord[1] === start[1]) {
styles.push(createSegmentStyle(start, null, rotation));
}
styles.push(createSegmentStyle(end, firstCoord, rotation));
});
return styles;
}
const map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.Stamen({ layer:'toner-lite' })
}),
new ol.layer.Vector({
source: lineSource,
style: styleFunction
})
],
view: new ol.View({
center: ol.proj.transform(
[35, 45], 'EPSG:4326', 'EPSG:3857'),
zoom: 4
})
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.5.0/ol.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.5.0/ol-debug.js"></script>
<div id="map" style="height:300px"></div>
Is it possible in OpenLayers 3 to create a text label which clones multiple times along a linestring feature, depending on a scale? Something like:
Here you can see, that when we change scale label "IX Corps Blvd" appears twice. How can we implement this?
You can achieve this with style function. My code sample is about making arrows to line string (slightly different case), but I have commented parts necessary to be changed (at least):
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var source = new ol.source.Vector();
var styleFunction = function(feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({ // apply street style here
color: '#ffcc33',
width: 2
})
})
];
geometry.forEachSegment(function(start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
// arrows
styles.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.Icon({ // Use here label, not icon.
src: 'http://openlayers.org/en/v3.17.1/examples/data/arrow.png',
anchor: [0.75, 0.5],
rotateWithView: false,
rotation: -rotation
})
}));
});
return styles;
};
var vector = new ol.layer.Vector({
source: source,
style: styleFunction
});
map.addInteraction(new ol.interaction.Draw({
source: source,
type: /** #type {ol.geom.GeometryType} */ ('LineString')
}));
Some more effort is needed to place titles in correct placements. I left this answer like this to serve a solid starting point for building your feature.
My source:
[1] http://openlayers.org/en/master/examples/line-arrows.html
I have problem with my OpenLayer3 map. When I add some markers to map I want to resize my map and change the zoom so that all markers were set on the screen.
My code looks like:
/** CREATE MARKERS **/
for (var i=0;i<1;i++){
var iconFeature = new ol.Feature({
geometry: new
ol.geom.Point(ol.proj.transform([Math.random()*360-180, Math.random()*180-90], 'EPSG:4326', 'EPSG:3857'))
});
vectorSource.addFeature(iconFeature);
var newBound = ol.Bounds();
newBound.extend([Math.random()*360-180, Math.random()*180-90]);
map.zoomToExtent(newBound);
}
/** MARKER STYLE **/
var iconStyle = [
new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 1,
scale: 0.07,
src: 'marker.png'
}))
})
];
/** ADD LAYER VECTOR **/
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: iconStyle
});
/** INIT MAP **/
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
}),
vectorLayer
],
overlays: [overlay],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
Is there a way to zoom the map to markers?
You have some errors in your logic and in some OL references. First you should create an ol.Extent that contains all the markers. Then use the map's view to fit it in.
// create ten random markers
for (var i = 0; i < 10; i++) {
var point = new ol.geom.Point(ol.proj.transform([Math.random() * 50, Math.random() * 50], 'EPSG:4326', 'EPSG:3857'));
var iconFeature = new ol.Feature({
geometry: point
});
vectorSource.addFeature(iconFeature);
}
// make the map's view to zoom and pan enough to display all the points
map.getView().fit(vectorSource.getExtent(), map.getSize());
Here's a plunker:
https://plnkr.co/edit/KVL14vdOSqJBxZz44s3u?p=preview
Once your vector features has been drawn you may get the extent using:
vector.on('render',function(e){
var myextent = vector.getSource().getExtent();
})
And then you may zoom to this extent using:
map.getView().fit(myextent , map.getSize());
So if you are going to use the render event
vector.on('render',function(e){
map.getView().fit(vector.getSource().getExtent(), map.getSize());
})