I've got a map and have created a feature layer like this:
window.map = L.mapbox.map('map', 'example.wefk232sm')
.setView([homeLatitude, homeLongitude], initialZoom);
var myLayer = L.mapbox.featureLayer().addTo(map);
// Pass features to the map
myLayer.setGeoJSON(geoJson);
The geoJson object looks like this:
var geoJson = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
title: name,
other: "text",
'marker-color': '#54a743',
'stroke': '#428334',
url: link
},
geometry: {
type: 'Point',
coordinates: [longitude, latitude]
}
]
};
What I'm trying to do is open the popup relating to a particular feature from, say the name on the geoJson.features[0].properties object, but I can't work out how to do this.
I can access it on click with this:
myLayer.on('click', function(e) {
e.layer.openPopup();
});
Mapbox is v1.6.2
You should be able to grab properties.title, for example, with the following
myLayer.on('click', function(e) {
var title = e.layer.feature.properties.title;
// do something with the title
});
Related
I am looking for a answer that will solve my problem. I am highlighting an address based on geocoder searched coordinates. This same functionality is working perfect on the click on building but I do not want to click on building rather just highlight the building based on searched coordinates. I am providing code below:
map.addLayer(
{
id: "3d-buildings",
source: "composite",
"source-layer": "building",
type: "fill",
minzoom: 10,
paint: {
"fill-color": "#aaa",
},
},
labelLayerId
);
map.addSource("currentBuildings", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [],
},
});
map.addLayer(
{
id: "highlight",
source: "currentBuildings",
type: "fill",
minzoom: 15,
paint: {
"fill-color": "#f00",
},
},
labelLayerId
);
This below click working perfect
map.on("click","3d-buildings", (e) => {
map.getSource("currentBuildings").setData({
type: "FeatureCollection",
features: e.features,
});
});
I want the same features but not on click rather than on geocoder result coordinates:
geocoder.on("result", (e) => {
var coordinates = e.result.geometry.coordinates;
const selectedFeatures = map.querySourceFeatures(coordinates, {
layers: ["3d-buildings"],
});
console.log(selectedFeatures); //giving blank array, how can I get the features same as the onclick function is providing with additional parameter which is 3d-buildings
map.getSource("currentBuildings").setData({
type: "FeatureCollection",
features: e.features,
});
});
Maybe I am wrong at some point in using querySourceFeature. Please direct me in right direction.
I found the below code in the MapBox website, I am unable to find out how exactly the data is received to plot the data-driven circles on the map. There is a url "mapbox://examples.8fgz4egr" present in the 'source' but what kind of data is it ? is it json or what ? How do I change the source and put my own ?
https://www.mapbox.com/mapbox-gl-js/example/data-driven-circle-colors/
<script> mapboxgl.accessToken = 'ACCESS_TOKEN; var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
zoom: 12,
center: [-122.447303, 37.753574] });
map.on('load', function () {
map.addLayer({
'id': 'population',
'type': 'circle',
'source': {
type: 'vector',
url: 'mapbox://examples.8fgz4egr'
},
'source-layer': 'sf2010',
'paint': {
// make circles larger as the user zooms from z12 to z22
'circle-radius': {
'base': 1.75,
'stops': [[12, 2], [22, 180]]
},
// color circles by ethnicity, using data-driven styles
'circle-color': {
property: 'ethnicity',
type: 'categorical',
stops: [
['White', '#fbb03b'],
['Black', '#223b53'],
['Hispanic', '#e55e5e'],
['Asian', '#3bb2d0'],
['Other', '#ccc']]
}
}
}); }); </script>
It's vector tiles as you can see from the type value of the source property. Here is an in depth explanation on what vector tiles are and how they work: https://www.mapbox.com/vector-tiles/
Very roughly it's GeoJSON sliced into map tiles.
For simplicity's sake you can switch out the source for a geojson source and connect the circle layer to it:
map.addLayer({
type: 'circle',
id: 'my-layer',
source: {
type: 'geosjon'
data: /* url to GeoJSON or inlined FeaturedCollection */
}
})
I want to do some simple things on a basemap project.
Such as creating a circle.
Creating a popup when click on created point.
Converting lat long to x y
How can I do these things?
var pt = new Point({
longitude: 99.909550,
latitude: 99.751906
});
var lineAtt = {
Name: "fill",
Owner: "fill",
Length: "999 km"
};
// Create a graphic and add the geometry and symbol to it
var pointGraphic = new Graphic({
geometry: pt,
symbol: markerSymbol,
attributes: lineAtt,
popupTemplate: { // autocasts as new PopupTemplate()
title: "{Name}",
content: [{
type: "fields",
fieldInfos: [{
fieldName: "Name"
}, {
fieldName: "Owner"
}, {
fieldName: "Length"
}]
}]
}
});
I found the solution that open popup while clicking the created point.
I'm trying to display a GeoJSON polygon on a map. I've used the example provided by OpenLayers with the following data, but only the second polygon is displayed:
var geojsonObject = {
"type": "FeatureCollection",
"crs": {
"type": "name",
},
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[103.92240800000013,21.69931],[100.93664,21.66959500000013],[108.031899,18.67076]]]
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[-5e6, -1e6], [-4e6, 1e6], [-3e6, -1e6]]]
}
}
]
};
The code I'm using to parse and add the GeoJSON to the map is as follows:
var vectorSource = new ol.source.Vector({
features: (new ol.format.GeoJSON()).readFeatures(geojsonObject)
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: styleFunction
});
I noticed different kinds of coordinates. In the second set the coordinates are represented like [-5e6, -1e6] with the e which I don't understand and in the first set - that don't work - they look like [103.92240800000013, 21.69931].
Is this a possible reason why my polygon is not displayed?
The problem is your two polygons are specified using different coordinate spaces and you need to determine which map projection you are going to use. By default OpenLayers uses something they call a "spherical mercator" and without delving into the detail the geometry coordinates are represented by pixels on a 2D plane.
Ideally, you would fix your GeoJSON to provide all coordinates in the same projection. If you can't do that, here is a working solution:
The set that you say aren't working look like longitude and latitude (GIS) coordinates and need to be transformed if they are to be displayed on the same layer - in the following example I've tagged the features that require transform using the GeoJSON properties like so:
var geojsonObject = {
type: 'FeatureCollection',
// ...
features: [
{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [/* ... */],
properties: {
requiresTransform: true // <- custom property
}
}
},
// ...
]
};
Before adding features to the layer source you could then do something like the following:
var features = (new ol.format.GeoJSON()).readFeatures(geojsonObject);
features.forEach(function(feature){
if(!feature.get('requiresTransform'))
return; // ignore
var geometry = feature.getGeometry(),
coords = geometry.getCoordinates();
if(geometry instanceof ol.geom.Polygon)
geometry.setCoordinates(transformPolyCoords(coords));
});
function transformPolyCoords(/* Array */ a){
return a.map(function(aa){
return aa.map(function(coords){
return ol.proj.transform(coords, 'EPSG:4326', 'EPSG:3857');
});
});
}
There may be a cleaner way of managing this and I'd imagine it involves keeping the separate formats in separate GeoJSON objects and I don't know how close it is to what you were expecting, but this is what I came up with using what you provided ยป working example.
Note: I know there's another question similar to this but it hasn't been answered and I need to know how mixed projections can be dealt with with GeoJSON and OSM.
I'm so confused. I was using the OSMDroid API on Android for mapping and wanted to replicate it using OpenLayers and GeoExt, but I've got a projection problem with including GeoJSON nodes and action events.
My tile set is OSM based, and is hosted on the same Web server as this HTML/JS. See it all below. I realize my boundaries aren't working, and my projections might be completely wrong. I've been testing different combinations.
The problem is my map displays correctly and is centered fine. However:
My GeoJSON feature nodes are way off the map. They're in a different projection long/lat, but I don't know how to set or convert GeoJSON long/lat to the current map projection.
My mapCtrl doesn't work. When I click it the lonlat is another projection (the OSM projection coords) and I can't seem to convert them)
Any tips on how extent/bounds actually work would be greatly appreciated
Can someone please help with a bit of projection advice? Sigh... I'm not patient enough for this.
Here's my full JS, as is:
var mapPanel, store, gridPanel, mainPanel, nodePop, mapPop;
Ext.onReady(function() {
var map, mapLayer, vecLayer;
var lon = -70.885610;
var lat = 38.345822;
var zoom = 17;
var maxZoom = 18;
var toProjection = new OpenLayers.Projection("EPSG:4326");
var fromProjection = new OpenLayers.Projection("EPSG:900913");
var extent = new OpenLayers.Bounds(-1.32,51.71,-1.18,51.80).transform(fromProjection, toProjection);
// Setup the node layer feature store and push it all into a vector layer
vecLayer = new OpenLayers.Layer.Vector("vector");
store = new GeoExt.data.FeatureStore({
layer: vecLayer,
fields: [
{name: 'name', type: 'string'},
{name: 'status', type: 'string'}
],
proxy: new GeoExt.data.ProtocolProxy({
protocol: new OpenLayers.Protocol.HTTP({
url: "data/sa.json",
format: new OpenLayers.Format.GeoJSON()
})
}),
autoLoad: true
});
// Setup the basic map layer using OSM style tile retreival to pull tiles
// from the same server hosting this service
map = new OpenLayers.Map(
'map', {
controls:[
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.ScaleLine()],
projection: toProjection,
displayProjection: fromProjection,
numZoomLevels: 20,
fractionalZoom: true
});
mapLayer = new OpenLayers.Layer.OSM(
"Local Tiles",
"tiles/${z}/${x}/${y}.png",
{
zoomOffset: 17,
resolutions: [1.194328566741945,0.5971642833709725,0.2985821416854863] // Zoom level 17 - 19
});
map.addLayers([mapLayer, vecLayer]);
// Create a map panel
mapPanel = new GeoExt.MapPanel({
title: "Map",
region: "center",
map: map,
xtype: "gx_mappanel",
center: new OpenLayers.LonLat(lon, lat),
zoom: zoom
});
// Create a grid panel for listing nodes
gridPanel = new Ext.grid.GridPanel({
title: "Nodes",
region: "east",
store: store,
width: 275,
columns: [{
header: "Name",
width: 200,
dataIndex: "name"
}, {
header: "Status",
width: 75,
dataIndex: "status"
}],
sm: new GeoExt.grid.FeatureSelectionModel({
autoPanMapOnSelection: true
})
});
// Create the main view port
new Ext.Viewport({
layout: "border",
items: [{
region: "north",
contentEl: "title",
height: 150
}, mapPanel, gridPanel]
});
var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.setCenter(lonLat, zoom);
// Attach all the event driven stuff here...
// Create a node selection pop up control
function nodeAction(feature) {
nodePop = new GeoExt.Popup({
title: 'Node selected',
location: feature,
width: 200,
html: "",
maximizable: true,
collapsible: true
});
nodePop.on({
close: function() {
if(OpenLayers.Util.indexOf(vectorLayer.selectedFeatures, this.feature) > -1) {
selectCtrl.unselect(this.feature);
}
}
});
nodePop.show();
};
// Attach the pop to node/feature selection events
var selectCtrl = new OpenLayers.Control.SelectFeature(vecLayer);
vecLayer.events.on({
featureselected: function(e) {
nodeAction(e.feature);
}
});
// Create map selection pop up control
function mapAction(lonlat) {
mapPop = new GeoExt.Popup({
title: 'Map selected',
location: lonlat,
width: 200,
html: "You clicked on (" + lonlat.lon.toFixed(2) + ", " + lonlat.lat.toFixed(2) + ")",
maximizable: true,
collapsible: true,
map: mapPanel.map,
anchored: true
});
mapPop.doLayout();
mapPop.show();
};
var mapCtrl = new OpenLayers.Control.Click({
trigger: function(evt) {
var lonlat = mapPanel.map.getLonLatFromViewPortPx(evt.xy);
lonlat.transform(new OpenLayers.Projection("EPSG:4326"), mapPanel.map.getProjectionObject());
//.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
mapAction(lonlat);
}
});
mapPanel.map.addControl(mapCtrl);
mapCtrl.activate();
});
// A control to handle user clicks on the map
OpenLayers.Control.Click = OpenLayers.Class(
OpenLayers.Control, {
defaultHandlerOptions: {
single: true,
double: false,
pixelTolerance: 0,
stopSingle: true
},
initialize: function(options) {
this.handlerOptions = OpenLayers.Util.extend(
options && options.handlerOptions || {},
this.defaultHandlerOptions
);
OpenLayers.Control.prototype.initialize.apply(
this, arguments
);
this.handler = new OpenLayers.Handler.Click(
this,
{ click: this.trigger },
this.handlerOptions
);
},
CLASS_NAME: "OpenLayers.Control.Click"
}
);
Here's the GeoJSON I'm using:
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
-70.3856,
38.3458
]
},
"type": "Feature",
"properties": {
"name": "Node0",
"status": "Active",
"externalGraphic": "img/node2.png",
"graphicHeight": 75, "graphicWidth": 75
},
"id": 100
},
{
"geometry": {
"type": "Point",
"coordinates": [
-70.885810,
38.344722
]
},
"type": "Feature",
"properties": {
"name": "Node1",
"status": "Active",
"externalGraphic": "img/node2.png",
"graphicHeight": 75, "graphicWidth": 75
},
"id": 101
}
]
}
Ok, here's how I dealt with the issue:
I'm using the embedded the Jetty Web server in my back-end, but
regardless, I created a servlet to respond with GeoJSON format data.
Each Feature location lon/lat is converted between projections.
(e.g. EPSG:4326 to EPSG:900913)
The lon/lat projection conversation leveraged the GeoTools Java API.
This blog post was particularly helpful
(http://ariasprado.name/2012/08/13/quick-and-dirty-coordinate-transforming-using-geotools.html)
Note that you'll need to go through a fair bit of trial and error if
you only want to include the jars required for converting yout
projections. GeoTools is large, does a lot, and has a number of
jars.
Now when the GeoExt.data.ProtocolProxy loads my GeoJSON content it's already in OSM compatible EPSG:900913. I would have liked to deal with this entirely in GeoExt/OpenLayer, but there doesn't appear to be an easy way. I will acknowledge that GeoExt and OpenLayers don't have super great reference documentation to follow.
I'd include my GeoTools code but "Arias Prado GIS Ramblings" blog post above does a better job than I could. Again though, note that you'll have to trial and error the jars. Projection encoders are loaded dynamically, and they in turn have class dependencies from other jars.