I am trying to add circle with latitude,longitude and radius(in meter or kilometer) when a button clicked.
I can add a circle on button clicked but it takes radius as a number between 1-25.
I need to give radius in meter
Note: when I draw a circles with finger gestures , I can get its radius in meter with this code
var radius = geometry.getRadius();
My drawing with finger gesture function:
function addInteraction() {
draw = new ol.interaction.Draw({
source: source,
type: shapetype,
freehand: true
});
map.addInteraction(draw);
To add a circle to the map:
var centerLongitudeLatitude = ol.proj.fromLonLat([longitude, latitude]);
var layer = new ol.layer.Vector({
source: new ol.source.Vector({
projection: 'EPSG:4326',
features: [new ol.Feature(new ol.geom.Circle(centerLongitudeLatitude, 4000))]
}),
style: [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'blue',
width: 3
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
})
]
});
map.addLayer(layer);
proof of concept fiddle
code snippet:
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([-117.1610838, 32.715738]),
zoom: 12
})
});
var centerLongitudeLatitude = ol.proj.fromLonLat([-117.1610838, 32.715738]);
var layer = new ol.layer.Vector({
source: new ol.source.Vector({
projection: 'EPSG:4326',
// radius = 4000 meters
features: [new ol.Feature(new ol.geom.Circle(centerLongitudeLatitude, 4000))]
}),
style: [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'blue',
width: 3
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
})
]
});
map.addLayer(layer);
html,
body {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
.map {
height: 100%;
width: 100%;
}
<link href="https://openlayers.org/en/v4.6.5/css/ol.css" rel="stylesheet" />
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
<div id="map" class="map"></div>
You just need to do the following
var coordsLongitudeLatitude = [1, 44]
# Convert to map coordinates (usually Spherical Mercator also named EPSG 3857)
var center = ol.proj.fromLonLat(coordsLongitudeLatitude)
# Create Circle geometry, 4000 = distance in meters
var circleGeometry = new ol.geom.Circle(center, 4000);
# If you want/need to transform it to a polygon
var polygonFromCircleGeometry = ol.geom.Polygon.fromCircle(circleGeometry);
Related
I'm using OpenLayers V4 and I'm trying to see if it's possible to allow a user to click on a feature's vector label and move/drag it to a location of their choice. My initial thought was to capture when a user clicked on the label, and then dynamically calculate and set the offsetX and offsetY properties of the label (ol.style.Text) as the user's mouse pointer moved around. To achieve this, I need to capture when the user clicks on the label and not the feature itself. The main problem is that I can't find a way to distinguish this. It appears as though the label is part of the vector feature because clicking on the feature highlights both the feature and the label and vice versa.
In summary, my question is two fold:
Does anyone have an idea how to create a user draggable vector label in OpenLayers 4?
Is there a way to detect/distinguish between a user clicking on a vector feature itself, or the vector label.
Note: I'm familiar with overlays and realize they might be easier to work with since they have a setPosition property, but the way my web map is constructed I need to display vector labels for each feature and not overlays
It is possible using vector labels in OpenLayers 6 where the modify interaction has access to the features being modified in its style function and can use hit detection of offset labels, but that is not available in version 4. In this example labels move with their features, but can also be moved independently of the features. Clones are needed to avoid changing feature geometries while moving the labels. The labels geometries are then restored and replaced with offsets for styling. When a feature is moved its label clone is kept in sync.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/build/ol.js"></script>
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script>
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var modifyStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: white,
width: width / 2
})
}),
zIndex: Infinity
});
var labelStyle = new ol.style.Style({
text: new ol.style.Text({
offsetY: 10,
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: '#000',
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 3,
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0 ,0, 0, 0)',
}),
}),
});
var featureLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'https://mikenunn.net/data/world_cities.geojson',
format: new ol.format.GeoJSON(),
}),
});
var labelLayer = new ol.layer.Vector({
source: new ol.source.Vector(),
renderBuffer: 1e3,
style: function (feature) {
labelStyle.getText().setOffsetX(feature.get('offsetX') || 0);
labelStyle.getText().setOffsetY((feature.get('offsetY') || 0) - 10);
labelStyle.getText().setText(feature.get('CITY_NAME'));
return labelStyle;
},
});
featureLayer.getSource().on('addfeature', function(event) {
var id = event.feature.getId();
var feature = event.feature.clone();
feature.setId(id);
labelLayer.getSource().addFeature(feature);
});
featureLayer.getSource().on('removefeature', function(event) {
var id = event.feature.getId();
var source = labelLayer.getSource();
source.removeFeature(source.getFeatureById(id));
});
var defaultStyle = new ol.interaction.Modify({
source: featureLayer.getSource()
}).getOverlay().getStyleFunction();
var featureModify = new ol.interaction.Modify({
source: featureLayer.getSource(),
style: function(feature) {
feature.get('features').forEach( function(modifyFeature) {
var id = modifyFeature.getId();
var geometry = feature.getGeometry().clone();
labelLayer.getSource().getFeatureById(id).setGeometry(geometry);
});
return defaultStyle(feature);
}
});
var labelModify = new ol.interaction.Modify({
source: labelLayer.getSource(),
hitDetection: labelLayer,
style: function(feature) {
var styleFeature;
feature.get('features').forEach( function(modifyFeature) {
var id = modifyFeature.getId();
styleGeometry = featureLayer.getSource().getFeatureById(id).getGeometry();
});
modifyStyle.setGeometry(styleGeometry);
return modifyStyle;
}
});
labelModify.on('modifyend', function(event) {
event.features.forEach( function(feature) {
var id = feature.getId();
var labelCoordinates = feature.getGeometry().getCoordinates();
var geometry = featureLayer.getSource().getFeatureById(id).getGeometry().clone();
var featureCoordinates = geometry.getCoordinates();
var resolution = map.getView().getResolution();
var offsetX = (labelCoordinates[0] - featureCoordinates[0]) / resolution + (feature.get('offsetX') || 0);
var offsetY = (featureCoordinates[1] - labelCoordinates[1]) / resolution + (feature.get('offsetY') || 0);
feature.set('offsetX', offsetX, true);
feature.set('offsetY', offsetY, true);
feature.setGeometry(geometry);
});
});
var map = new ol.Map({
layers: [featureLayer, labelLayer],
interactions: ol.interaction.defaults().extend([labelModify, featureModify]),
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([5, 51]),
zoom: 8
})
});
</script>
</body>
</html>
I searched for 2 hours now, but it's still not clear if it's possible or not in OL3.
I would like my icons to be fixed size (not to the screen, but to the image map I'm using). I mean, it should cover the same area even if I'm zoomed out, and not covering the half of the map (like I was using a circle polygon, but I have complex Icons so I have to use it as point features). Is there any solution to it?
Like in QGIS: MAP UNITS.
I already have these:
var jelekStyle = function(feature, resolution) {
if(feature.get('tipus')=== 'falu') {
icon = '00_ikonok/falu.png',
size = [115, 233],
scale = 0.05,
anchor = [0.5,46];
} else if(feature.get('tipus')=== 'puszta') {
image = '00_ikonok/puszta.png';
} ...
}
return [new ol.style.Style({
image: new ol.style.Icon({
src: icon,
scale: scale,
size: size,
anchor: anchor,
anchorXUnits: 'fraction',
anchorYUnits: 'pixels'
})
})];
};
...
var jelek = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'sopron_honlap/json/Gorog-Kerekes_Sopron_jelek_GeoJSON.geojson',
format: new ol.format.GeoJSON()
}),
updateWhileAnimating: true,
updateWhileInteracting: true,
style: jelekStyle
});
Yes, there is a solution. In a style function on the layer, you have to scale your icon size by a reference resolution divided by the render resolution.
To update the style even during user interaction, configure your layer with updateWhileInteracting: true and updateWhileAnimating: true. Here is the whole code:
var iconFeature = new ol.Feature(new ol.geom.Point([0, 0]));
var iconStyle = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'https://openlayers.org/en/v4.3.2/examples/data/icon.png'
})
});
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
updateWhileAnimating: true,
updateWhileInteracting: true,
style: function(feature, resolution) {
iconStyle.getImage().setScale(map.getView().getResolutionForZoom(3) / resolution);
return iconStyle;
}
});
var rasterLayer = new ol.layer.Tile({
source: new ol.source.TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json?secure',
crossOrigin: ''
})
});
var map = new ol.Map({
layers: [rasterLayer, vectorLayer],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
html, body, #map {
margin: 0;
width: 100%;
height: 100%;
}
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="https://openlayers.org/en/v4.3.2/css/ol.css">
<script src="https://openlayers.org/en/v4.3.2/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
</body>
I would like to display a polyline so that the vertices can not be moved, deleted or added, ie exactly like when the editable attribute is set to false, but the circles which are present when the editable attribute is set to true are still visible so that they can be clicked and a vertex number obtained.
So the polyline code could be:
newPoly = new google.maps.Polyline({
strokeColor: '#08088a',
strokeWeight: 2,
editable: false
});
Is this possible?
One option: process through the polyline, add circular markers to each vertex in the line with the vertex number in the marker's infowindow.
Related question: Google Maps V3 Polyline : make it editable without center point(s)
proof of concept fiddle
code snippet:
function initialize() {
var infowindow = new google.maps.InfoWindow();
var map = new google.maps.Map(
document.getElementById("map_canvas"), {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var polyCoord = [
new google.maps.LatLng(41.86, 8.73),
new google.maps.LatLng(41.88, 8.75),
new google.maps.LatLng(42, 8),
new google.maps.LatLng(43.5, 9)
];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < polyCoord.length; i++) {
bounds.extend(polyCoord[i]);
var marker = new google.maps.Marker({
position: polyCoord[i],
title: '#0',
map: map,
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillColor: 'white',
fillOpacity: 1,
scale: 3,
strokeColor: 'black',
strokeWeight: 1,
strokeOpacity: 1,
// anchor: new google.maps.Point(200, 200)
}
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent("vertex #" + i + "<br>coord: (" + this.getPosition().toUrlValue(6) + ")");
infowindow.open(map, marker);
}
})(marker, i));
}
map.fitBounds(bounds);
// Polyline
var newPoly = new google.maps.Polyline({
strokeColor: '#08088a',
strokeWeight: 2,
editable: false,
path: polyCoord,
map: map
});
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>
How do I get the svg image is static when I zoom in on the map, which always remains in the same place.
This is my fiddle
If I use png images works , but it is not visually well for me and is not what i'm looking for.
Help is appreciated
Sorry for my english.
new Fiddle
The anchor is expected to be a Point, not a LatLng.
The default-acnchor is the bottom-middle of the icon, as it seems you need to set it to the top-left, so it has to be:
new google.maps.Point(0,0)
When you want to have a scaled icon based on the zoom you must calculate the scale-property and re-assign the icon to the marker.
The formula would be(assuming the scale-factor at zoom 12 is 1):
Math.pow(2,map.getZoom()-12)
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(-32.95041520, -60.66641804),
zoom: 12,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
triangleCoords = [
new google.maps.LatLng(-32.93831432, -60.69379806),
new google.maps.LatLng(-32.96337859, -60.67860603),
new google.maps.LatLng(-32.96352262, -60.66633224),
new google.maps.LatLng(-32.95041520, -60.66641807)
];
var bermudaTriangle = new google.maps.Polygon({
paths: triangleCoords,
IsInactivo: true
});
bermudaTriangle.setMap(map);
var bounds = new google.maps.LatLngBounds();
var i;
for (i = 0; i < triangleCoords.length; i++) {
bounds.extend(triangleCoords[i]);
}
console.log(bounds.getCenter());
centroPolygon = bounds.getCenter();
var inactive = new google.maps.MVCObject();
inactive.set('icon', {
path: 'M27.314 4.686c-3.022-3.022-7.040-4.686-11.314-4.686s-8.292 1.664-11.314 4.686c-3.022 3.022-4.686 7.040-4.686 11.314s1.664 8.292 4.686 11.314c3.022 3.022 7.040 4.686 11.314 4.686s8.292-1.664 11.314-4.686c3.022-3.022 4.686-7.040 4.686-11.314s-1.664-8.292-4.686-11.314zM28 16c0 2.588-0.824 4.987-2.222 6.949l-16.727-16.727c1.962-1.399 4.361-2.222 6.949-2.222 6.617 0 12 5.383 12 12zM4 16c0-2.588 0.824-4.987 2.222-6.949l16.727 16.727c-1.962 1.399-4.361 2.222-6.949 2.222-6.617 0-12-5.383-12-12z',
fillColor: '#FF5858',
fillOpacity: 0.4,
scale: 1,
strokeColor: '#FF5858',
strokeWeight: 1,
//set the anchor to the top left corner of the svg
anchor: new google.maps.Point(0, 0)
});
google.maps.event.addListener(map, 'zoom_changed', function() {
inactive.get('icon').scale = Math.pow(2, this.getZoom() - 12);
//tell the marker that the icon has changed
inactive.notify('icon');
});
google.maps.event.trigger(map, 'zoom_changed');
new google.maps.Marker({
map: map,
position: centroPolygon
}).bindTo('icon', inactive, 'icon');
}
google.maps.event.addDomListener(window, 'load', initialize)
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&.js"></script>
<div id="map-canvas"></div>
I was wondering whether it is possible to use icon font icons (e.g. Font Awesome) as markers in Google Maps V3 to replace the default marker. To show/insert them in a HTML or PHP document the code for the marker would be:
<i class="icon-map-marker"></i>
I just had the same problem - decided to do a quick and dirty conversion and host on github.
https://github.com/nathan-muir/fontawesome-markers
You can manually include the JS file, or use npm install fontawesome-markers or bower install fontawesome-markers.
Just include the javascript file fontawesome-markers.min.js and you can use them like so:
new google.maps.Marker({
map: map,
icon: {
path: fontawesome.markers.EXCLAMATION,
scale: 0.5,
strokeWeight: 0.2,
strokeColor: 'black',
strokeOpacity: 1,
fillColor: '#f8ae5f',
fillOpacity: 0.7
},
clickable: false,
position: new google.maps.LatLng(lat, lng)
});
Edit (April-2016): There's now packages for v4.2 -> v4.6.1
I know this is an old post, but just in case you can use the MarkerLabel object now:
var marker = new google.maps.Marker({
position: location,
map: map,
label: {
fontFamily: 'Fontawesome',
text: '\uf299'
}
});
Worked for me.
.
Reference Google Maps Maker
Here's my attempt at the same thing (using "markerwithlabel" utility library) before I realised Nathan did the same more elegantly above: http://jsfiddle.net/f3xchecf/
function initialize() {
var myLatLng = new google.maps.LatLng( 50, 50 ),
myOptions = {
zoom: 4,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
},
map = new google.maps.Map( document.getElementById( 'map-canvas' ), myOptions ),
marker = new MarkerWithLabel({
position: myLatLng,
draggable: true,
raiseOnDrag: true,
icon: ' ',
map: map,
labelContent: '<i class="fa fa-send fa-3x" style="color:rgba(153,102,102,0.8);"></i>',
labelAnchor: new google.maps.Point(22, 50)
});
marker.setMap( map );
}
initialize();
The light weight solution
fontawesome-markers: 480kb
markerwithlabel: 25kb
To avoid these dependencies, simple go to fontawesome-markers, find the path for the icon you want, and include it as follows:
var icon = {
path: "M27.648-41.399q0-3.816-2.7-6.516t-6.516-2.7-6.516 2.7-2.7 6.516 2.7 6.516 6.516 2.7 6.516-2.7 2.7-6.516zm9.216 0q0 3.924-1.188 6.444l-13.104 27.864q-.576 1.188-1.71 1.872t-2.43.684-2.43-.684-1.674-1.872l-13.14-27.864q-1.188-2.52-1.188-6.444 0-7.632 5.4-13.032t13.032-5.4 13.032 5.4 5.4 13.032z",
fillColor: '#E32831',
fillOpacity: 1,
strokeWeight: 0,
scale: 0.65
}
marker = new google.maps.Marker({
position: myLatlng,
map: map,
icon: icon
});
In a modern browser one can use the canvas in order to render the font to png, and then use the data URI scheme:
function getIcon(glyph, color) {
var canvas, ctx;
canvas = document.createElement('canvas');
canvas.width = canvas.height = 20;
ctx = canvas.getContext('2d');
if (color) {
ctx.strokeStyle = color;
}
ctx.font = '20px FontAwesome';
ctx.fillText(glyph, 0, 16);
return canvas.toDataURL();
}
For example: getIcon("\uf001") for the music note.
If you want the awesomefont MARKER with an awesomefont ICON INSIDE:
1. copy the SVG path of the awesomefont marker (click download and copy the SVG path) and use it as icon (remember to credit the authors, see license).
Then you can change it's color to anything you want.
2. As label you only insert the awesome font icon code and the color you want.
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<div id="map"></div>
<script>
function init() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 6,
center: new google.maps.LatLng(51.509865, -0.118092)
});
var icon = {
path: "M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z", //SVG path of awesomefont marker
fillColor: '#333333', //color of the marker
fillOpacity: 1,
strokeWeight: 0,
scale: 0.09, //size of the marker, careful! this scale also affects anchor and labelOrigin
anchor: new google.maps.Point(200,510), //position of the icon, careful! this is affected by scale
labelOrigin: new google.maps.Point(205,190) //position of the label, careful! this is affected by scale
}
var marker = new google.maps.Marker({
position: map.getCenter(),
map: map,
icon: icon,
label: {
fontFamily: "'Font Awesome 5 Free'",
text: '\uf0f9', //icon code
fontWeight: '900', //careful! some icons in FA5 only exist for specific font weights
color: '#FFFFFF', //color of the text inside marker
},
});
}
google.maps.event.addDomListener(window, 'load', init);
</script>
It is possible to import the svgs directly from #fortawesome/free-solid-svg-icons and use the Icon Interface.
import { faMapMarkerAlt } from "#fortawesome/free-solid-svg-icons";
function initMap(): void {
const center = { lat: 0, lng: 0 };
const map = new google.maps.Map(
document.getElementById("map") as HTMLElement,
{
zoom: 9,
center,
}
);
new google.maps.Marker({
position: { lat: 0, lng: 0 },
map,
icon: {
path: faMapMarkerAlt.icon[4] as string,
fillColor: "#0000ff",
fillOpacity: 1,
anchor: new google.maps.Point(
faMapMarkerAlt.icon[0] / 2, // width
faMapMarkerAlt.icon[1] // height
),
strokeWeight: 1,
strokeColor: "#ffffff",
scale: 0.075,
},
});
}
Can try it at: https://codesandbox.io/embed/github/googlemaps/js-samples/tree/sample-marker-modern
I've put together a simple JS library that generates nice SVG markers using the Font Awesome icons. https://github.com/jawj/MapMarkerAwesome
All I seen looks good, but they would not work for me; However, this worked smoothly and is small.
Use a link out to wherever your font awesome library is.
The normal marker javascript code is fine and add the icon attribute.
// The marker
var marker = new google.maps.Marker({
position: uluru,
icon: 'https://cdn.mapmarker.io/api/v1/pin?icon=fa-truck&size=50&hoffset=0&color=%23FFFFFF&background=%23FF7500&voffset=-1',
map: map,
});
}
You can change the font awesome icon, position, color, etc. right there in the icon: attribute.