Related
I was able to correctly query data from the OSM API.
Then, I've been able to show nodes on the map with the following codes:
for (let i = 0; i < data.elements.length; i++) {
let pos;
let marker;
const e = data.elements[i];
if (e.id in this._ids) {
continue;
}
this._ids[e.id] = true;
if (e.type === 'node') {
pos = L.latLng(e.lat, e.lon);
}
else{
pos = L.latLng(e.center.lat, e.center.lon);
}
if (this.options.markerIcon) {
marker = L.marker(pos, { icon: this.options.markerIcon });
}
else {
marker = L.circle(pos, 80, {
stroke: false,
fillColor: '#0000ff',
fillOpacity: 0.9
});
}
}
which gives me the following visual output:
MyOutput-Image
How can I also show lines how it is done on OverpassTurbo:
OverpassTurbo-Image
What does your OSM API query looks like? I assume it's an overpass query, in which case, you might have put an out center at the end, which returns the center of each way.
Over pass out statement :
center: This adds only the centre of the above mentioned bounding box to ways and relations. Note: The center point is not guaranteed to lie inside the polygon (example).
Therefore, each way has a long/lat which is in the middle, which is what you plot as a marker using the e.center.lat
example of a way with out center :
{
"type": "way",
"id": 2263973,
"center": {
"lat": 51.5070645,
"lon": -0.1359499
},
"nodes": [
9789823,
9789817,
3933850766,
...
],
"tags": {...}
}
You could either go through each associated node, and look them up and get the lat and lon. Or use the out geom option which returns the coordinates or the nodes directly:
{
"type": "way",
"id": 2263973,
"bounds": {
"minlat": 51.5064574,
"minlon": -0.1363268,
"maxlat": 51.5076716,
"maxlon": -0.1355731
},
"nodes": [
9789823,
9789817,
...
],
"geometry": [
{ "lat": 51.5064574, "lon": -0.1355731 },
{ "lat": 51.5069432, "lon": -0.1360143 },
{ "lat": 51.5072896, "lon": -0.1363027 },
{ "lat": 51.5073314, "lon": -0.1363255 },
{ "lat": 51.5073531, "lon": -0.1363268 },
{ "lat": 51.5073965, "lon": -0.1363228 },
{ "lat": 51.5074324, "lon": -0.1363027 },
{ "lat": 51.5074691, "lon": -0.1362638 },
{ "lat": 51.5076716, "lon": -0.1356893 }
],
"tags": {...}
}
Notice how you also get the min and max values for latitude and in longitude in a bounds attribute. You can then go through the geometry array, extract all the lat and lon in a latlngs array, and use:
var polyline = L.polyline(latlngs, {color: 'blue'}).addTo(map); to draw a line. See Leaflet doc on polyline
And you can get this, for [highway~motorway]
I use this code to have clusters:
for (int index = 0; index < punti_di_interesse.length; index++) {
var point = {
"type": "Feature",
"id": index,
"properties": {
"id": index,
"name": punti_di_interesse[index].name,
'descrizione': punti_di_interesse[index].descrizione,
},
"geometry": {
"type": "Point",
"coordinates": [
punti_di_interesse[index].longitude,
punti_di_interesse[index].latitude,
0.0
]
}
};
allSymbolGEOJSON.add(point);
}
var allPoints = {
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"}
},
"features": allSymbolGEOJSON,
};
var source = await controller.addSource(
"earthquakes",
GeojsonSourceProperties(
data: allPoints,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
),
);
await controller.addLayer(
"earthquakes",
"clusters",
CircleLayerProperties(circleColor: [
Expressions.step,
[Expressions.get, 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
], circleRadius: [
Expressions.step,
[Expressions.get, 'point_count'],
20,
100,
30,
750,
40
]),
);
await controller.addLayer(
"earthquakes",
"cluster-count",
SymbolLayerProperties(
textField: [Expressions.get, 'point_count_abbreviated'],
textSize: 12,
));
await controller.addSymbolLayer(
"earthquakes",
"unclustered-point",
SymbolLayerProperties(
textField: [Expressions.get, "name"],
textHaloWidth: 1,
textSize: 12.5,
textHaloColor: '#ffffff',
textOffset: [
Expressions.literal,
[0, 2]
],
iconImage: "assets/icona_stato-rosso.png",
iconSize: 2,
iconAllowOverlap: true,
textAllowOverlap: true,
textColor: '#000000',
textHaloBlur: 1,
),
filter: [
'!',
['has', 'point_count']
],
enableInteraction: true,
);
Under my custom iconImage I see a black dot, how can this be removed?
In addition, I need that when the iconImage is clicked, a modal opens with information that is contained in the data structure in "properties"
I have tried using controller.onFeatureTapped.add(onFeatureTap);
but in the onFeatureTap function how do I access properties from featureId, point or latLng?
Am I doing something wrong?
For anyone stumbling across this problem, i figured out the following:
the CircleLayerProperties set a standard #000000 color value for circles. This together with the fact that you recolor everything with a point_count (which singular symbols do not have) leads to the CircleLayer drawing a black circle.
To fix this, use expressions to set the circleOpacity to 0.0 for all the unclustered symbols like so:
circleOpacity: [
"case",
["has", "point_count"],
1.0,
[
"!",
["has", "point_count"]
],
0.0,
1.0
]
Edit:
To your second point, i can shed some light there too:
in general, your are on the right path, but let me put together a more complete example for everyone:
First, define your GeoJson with an id:
var point = {
"type": "Feature",
"id": index,
"properties": {
...
},
"geometry": {
...
}
};
Then, add a listener to your MapController:
mapController.onFeatureTapped.add((id, point, coordinates) {
print(id);
}
The print(id) in the above handler will then print the id you defined in your GeoJson (or the id of a cluster, if applicable).
Hope that helps someone!
I have an application where I can draw a route so a simulation start where a boat is following that route. What I want to know is how I could measure the distance between me and the first Circle that I draw in the route(so the start point of the boat)
the circle on the right is my current location and the circle on the left is the first dot that I have drawn.
this is how I get my current location
navigator.geolocation.getCurrentPosition(position => {
console.log(position.coords.latitude, position.coords.longitude);
});
and this is how I draw and get the coordinates of the route
// gives the function to be able to draw lines in the map to make a route
var draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
line_string: true
},
styles: [
// ACTIVE (being drawn)
// line stroke
{
"id": "gl-draw-line",
"type": "line",
"filter": ["all", ["==", "$type", "LineString"], ["!=", "mode", "static"]],
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#3b9ddd",
"line-dasharray": [0.2, 2],
"line-width": 4,
"line-opacity": 0.7
}
},
{
"id": "gl-draw-polygon-and-line-vertex-halo-active",
"type": "circle",
"filter": ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
"paint": {
"circle-radius": 10,
"circle-color": "#FFF"
}
},
// vertex points
{
"id": "gl-draw-polygon-and-line-vertex-active",
"type": "circle",
"filter": ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
"paint": {
"circle-radius": 6,
"circle-color": "#3b9ddd",
},
}
]
});
map.addControl(new mapboxgl.FullscreenControl());
map.addControl(geolocate)
map.addControl(new mapboxgl.NavigationControl());
map.addControl(draw);
// add create, update, or delete actions
map.on('draw.create', updateRoute);
map.on('draw.update', updateRoute);
map.on('draw.delete', removeRoute);
// use the coordinates you just drew to make your directions request
function updateRoute() {
removeRoute(); // overwrite any existing layers
var data = draw.getAll();
var lastFeature = data.features.length - 1;
coords = data.features[lastFeature].geometry.coordinates;
}
So basically I want to measure between the distance between position.coords.latitude, position.coords.longitude and coords[0]
You can calculate the distance between two coordinates using LngLat.distanceTo()
Something like:
const start = new Mapbox.LngLat(...coords);
const end = new Mapbox.LngLat(position.coords.longitude, position.coords.latitude);
const dist = start.distanceTo(end);
I want to show the outline of a circle on an interactive map (no fill) however, the paint options in mapbox-gl-js seem limited to fill only.
https://www.mapbox.com/mapbox-gl-style-spec/#layers-circle
var styles = [{
"id": 'points',
"interactive": true,
"type": "circle",
"source": "geojson",
"paint": {
"circle-radius": 5,
"circle-color": "#000
},
"filter": ["in", "$type", "Point"]
}, {
"type": "line",
"source": "geojson",
"layout": {
"line-cap": "round",
"line-join": "round"
},
"paint": {
"line-color": "#000",
"line-width": 2.5
},
"filter": ["in", "$type", "LineString"]
}];
Am i missing something or is this just not possible?
This is now possible, with circle-opacity.
E.g.:
"paint": {
"circle-opacity": 0,
"circle-stroke-width": 1,
"circle-stroke-color": #000
}
Not currently possible. Current top workaround appears to be layering two circles of slightly different sizes.
https://github.com/mapbox/mapbox-gl-js/issues/1713
https://github.com/mapbox/mapbox-gl-style-spec/issues/379
I'm having trouble running custom color 'match' and having opacity controls running simultaneously.
I can get both working, but not at the same time. See code below.
var coorAddresses = [ [ -75.7040473, 45.418067,"Medium" ], [-75.7040473, 45.418067, "Medium"], [-79.32930440000001, 43.7730495, "Unknown"]]
$.getJSON(coodAddresses, function(data) {
for(var itemIndex in data) {
// push new feature to the collection
featureCollection.push({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [data[itemIndex][0], data[itemIndex][1]]
},
"properties": {
"size_by": data[itemIndex][2],
"color_by": data[itemIndex][2]
},
});
}
});
map.on('load', function () {
map.addLayer({
"id": "points",
"type": "circle",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": featureCollection
}
},
"paint": {
"circle-color": [
'match',
['get', 'size_by'],
'Easy',
'#e4f400',
'Medium',
'#f48a00',
'Unknown',
'#6af400',
/* other */ '#00e4f4'
],
"circle-radius": [
'match',
['get', 'size_by'],
'Easy',
4,
'Medium',
7,
'Unknown',
2,
/* other */ 1000
],
// "circle-opacity": 0, // color does not show if i uncomment these lines
// "circle-stroke-width": 1, // do not get desired 'hollow' circle unless these lines run
}});
Trying to troubleshoot.
I am using Fusion Chart version 3.1.1 and using column 2d graph in IOS which is working fine.
I am also using link event in this like given below
<set label="1" value="14000" color="bbdaf3" link="JavaScript:myJS1('+Salary+')"/>\n\
So whenever I click on this particular bar myJS1 function is getting called and give the result as expected.
When i click on particular bar , it shows its associated value which 14000 on it which default chart (Hover) functionality . Instead of Can i change the particular bar color when i click on it for highlighting it.
It is possible to change the color of particular bar while clicking on it ( with latest version of FusionCharts ). You have to modify the underlying raphael object. An example can be found in this fiddle. http://jsfiddle.net/subramaniashiva/KmTZ9/6/ Let me know if this helps.
FusionCharts.ready(function () {
var revenueChart = new FusionCharts({
type: 'column2d',
renderAt: 'chart-container',
id: 'myChart',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Quarterly Revenue ",
"xAxisName": "Quarter",
"yAxisName": "Amount (In USD)",
"numberPrefix": "$",
"valueHoverAlpha": "100",
"plotHoverEffect": "0",
"theme": "fint"
},
"data": [{
"label": "Q1",
"value": "1950000"
}, {
"label": "Q2",
"value": "1450000"
}, {
"label": "Q3",
"value": "1730000"
}, {
"label": "Q4",
"value": "2120000"
}]
},
events: {
"dataPlotClick": function (evtObj, argObj) {
// Modifying the underlying Raphael object
var i, plotItems = evtObj.sender.jsVars.hcObj.elements.plots[0].items,
plotLength = plotItems.length;
for (i = 0; i < plotLength; i++) {
plotItems[i].graphic.attr("fill-opacity", 0.2);
}
plotItems[argObj.dataIndex].graphic.attr("fill-opacity", 1);
}
}
}).render();
});