Some three locations are connected in a triangle shape in Open Layer Map. I am trying to get all the three locations (latitude and longitude) with the help of OpenLayers and React JS. But unfortunately, I am able to get the Latitude and Longitude of visible view and not the marked layers.
When I used the below code, it is not fetching the expected long and lat and it is resulting the visible map long and lat.
var glbox = map.getView().calculateExtent(map.getSize());
var box = proj.transformExtent(glbox,'EPSG:3857','EPSG:4326');
console.log("Latitude and longitude :",box);
So, I have tried with the below options as well and it is not resulting the expected long and lat.
console.log("Long and Lat :",map.getFeaturesAtPixel()); //--> null
console.log("Long and Lat :",map.getLayers());
console.log("Long and Lat :",map.getFeaturesAtPixel()); //--> null
How can I get the latitude and longitude of the all three locations that are shown in the image?
It will never work the way you are currently doing things.
What do I mean? I mean that going through map.getFeaturesAtPixel is one way that can work but you didn't read the API docs. You need at least to provide pixel (x, y screen coordinates) to the function.
You can get pixel using the following
map.on('click', evt => {
console.log(evt.pixel);
})
I've done a simple demo to illustrate. Go to http://openlayers.org/en/latest/examples/gpx.html and paste the following code in the browser debugger console. Click on point(s) and observe the behavior in the console.
map.on('click', evt => {
var features = map.getFeaturesAtPixel(evt.pixel);
if (features) {
// Get name (but it depends of your data attributes)
console.log(features
.filter(feature => feature.getGeometry().getType() == 'Point')
.map(feature => feature.get('name')));
// Get the features, filter to only get Point, then get geometry
// and coordinates, change projection to lon lat
console.log(features
.filter(feature => feature.getGeometry().getType() == 'Point')
.map(feature => `Longitude, latitude: ${ol.proj.toLonLat(feature.getGeometry().getCoordinates()).join(', ')}`));
}
})
Edit due to feedback.
To get the points from a LineString, just do
var featuresLinestringPointsCoordinates = vector.getSource().getFeatures()
.map(feature => {
return feature
.getGeometry()
.clone()
.transform('EPSG:3857','EPSG:4326')
.getCoordinates();
});
console.log(featuresLinestringPointsCoordinates);
// More readable and we only get the first linestring
console.table(featuresLinestringPointsCoordinates[0])
Tested on the official snap demo after drawing a LineString
Related
I'm trying to make a graph using anygraph. It loads data from a csv file, but i am having trouble to get the eventmarkers from the same file.
I dont seem to get the mapping/source values correct for the eventMarkers.data method. My goal is to load the markers from the same csv file as the source of the graph, where 1 column will contain marker information for some dates.
Suppose i have the following csv:
date, value, optionalmarkerinfo
2021-01-01 01:00:00,2,
2021-01-01 01:00:00,3,markerinfo
and the following code:
anychart.data.loadCsvFile("export.csv", function (data) {
var dataTable = anychart.data.table(0, '');
dataTable.addData(data);
//Create table and stuff
var chart = anychart.stock(); // (the type of graph isnt correct for this data, but its only to generally give a skelet of my setup)
// more stuff where i create the first timelines graph
// then to add a marker on each timeframe:
// (data will be filtered later to only show markers on specific values of dates)
var dataSet = anychart.data.set(data);
var mappingMarker = dataSet.mapAs({date: 0});
chart.plot(1).eventMarkers().data(mappingMarker); // THIS DOESNT WORK
// finish the drawing:
chart.container('container');
chart.draw();
}
Unfortunately, the Stock data and mapping instance are not compatible with the event markers. You should apply the data directly as an array of objects. As a workaround, you can load a separated CSV file, preprocess it to the compatible format and apply it to event markers.
As a reaction to the suggestion of anychart to load a csv with the markers seperately i came to the next solution which worked:
anychart.data.loadCsvFile("markers.csv", function (data) {
var lines=data.split("\n");
var result = [];
for(var i=1;i<lines.length;i++){
var obj = {};
var currentline=lines[i].split(",");
obj["date"] = currentline[0];
obj["description"] = currentline[1];
result.push(obj);
}
// add the markers to the previously defined plot with the markers.
chart.plot(0).eventMarkers({"groups": [
{
"format": "A",
"data" : result
}
]});
I'm using azure map.
What's happening is that I have 2 layers. A layer that have Circles and a layer with polygons.
I have a functionality in which a popup appear when I click on a specific circle.
The issue occur when I add the polygon layer after the circle layer.
It's like the polygon layer is being drawn on top of the circle layer. In which it prevent the popup from appearing when clicking on the circle.
Here's how I'm adding the polygon layer:
showFetchedResultOnMap(facilities) {
const self = this;
if (facilities && facilities.length > 0) {
self.cleanRestrictionLayer();
//Create a data source and add it to the map.
self.datasource = new atlas.source.DataSource();
self.map.sources.add(self.datasource);
//Add a data set to the data source.
self.CleanMap();
//Create a data source and add it to the map.
var datasource = new atlas.source.DataSource();
self.map.sources.add(datasource);
self.map.imageSprite.add(self.chosenCategory, 'assets/svg/' + self.chosenCategory + '.svg')
.then(function () {
facilities.forEach(cat => {
datasource.add(new atlas.data.Feature(new atlas.data.Point([cat.longitude, cat.latitude])));
});
//Add a layer for rendering point data as symbols.
self.map.layers.add(new atlas.layer.SymbolLayer(datasource, self.chosenCategory, {
iconOptions: {
//Pass in the id of the custom icon that was loaded into the map resources.
image: self.chosenCategory,
//Optionally scale the size of the icon.
size: 0.1
}
}));
});
}
}
Anyone have an Idea about how I can fix this??
I'm not seeing a polygon layer in the code you provided. That said, when you add layers to the map, the order in which you add them is the z-index by default. Last one added goes on top. That said, when adding the layer using the map.layers.add function, there is a second parameter you can add in which can be another layer or layer id. When this is specified the layer you are adding will be inserted below that second specified layer. Here is the doc on this: https://learn.microsoft.com/en-us/javascript/api/azure-maps-control/atlas.layermanager?view=azure-maps-typescript-latest#add-layer---layer----string---layer-
Here is a short example:
map.layers.add(new atlas.layers.BubbleLayer(datasource, 'myBubbles'));
map.layers.add(new atlas.layers.PolygonLayer(datasource, 'myPolygons'), 'myBubbles');
My application shows a map with react-leaflet and uses LayersControl to switch between an OSM TileLayer and HERE TileLayer. The code is as follows:
<LayersControl position="topright">
<LayersControl.BaseLayer
name={this.props.intl.formatMessage({id:'map.normal_map'})}
checked={true}
>
{ tileLayerOSM }
</LayersControl.BaseLayer>
<LayersControl.BaseLayer name={this.props.intl.formatMessage({id:'map.terrain_map'})}>
{ tileLayerHERE }
</LayersControl.BaseLayer>
</LayersControl>
The problema I see is the following: when moving the OSM map, some 'squares' are downloaded from HERE while they are not ready with OSM. See the network trace:
I would like to avoid this behavior, since it is a bit annoying for the user, who see changes in the visualization for a short period of time.
I don't have experience using Leaflet with React, but these is clearly not the desired behaviour.
In Leaflet that (retrive the both base layers at the same time) happens when you add both to the map. Something like:
const accessToken = 'foo';
let osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
const mapbox = 'https://api.mapbox.com/styles/v1/mapbox/basic-9/tiles/256/{z}/{x}/{y}?access_token={accessToken}';
const map = L.map('map').setView([42.2, -8.8], 12);
map.addLayer(osm);
map.addLayer(mapbox); // only one should be added to the map
or directly when instantiating the map:
let map = L.map('map', {
center: [42.2, -8.8],
zoom: 12,
layers: [osm, mapbox] // only one should be added to the map
});
With this kind of baselayers you only must add one to the map and use the layer control to switch between one or the other. When only one is added only the tiles for one of the maps are requested, saving bandwith.
As a "shot in the dark" I will try to make the checked value explicit for all layers. First both as a harcoded false, nothing should be shown in the map. Then one with checked=true harcoded and the other with false, and so on. Probably the trouble is how those attributes are managed.
I have a Word 2016 Add-in that creates images using graphviz and stores the corresponding dot code in the altdescription of the image.
I can select the image and load the dot code back to the editor in the add-in. But this only works in my current implementation for inlinePictures.
function getDataFromSelection() {
Word.run(function (context) {
var range = context.document.getSelection();
var paragraphs = range.paragraphs;
context.load(paragraphs);
return context.sync().then(function () {
var pictures = paragraphs.items[0].inlinePictures;
context.load(pictures);
return context.sync().then(function () {
var picture = pictures.items[0];
editor.getSession().getDocument().setValue(picture.altTextDescription);
});
});
})
}
How can I obtain the selected picture if it is free floating in the document?
The Goal of the add in is to create and edit already created graphs using dot. But the editing part is currently the problem.
great question. as you properly deduced the inlinePictures collection only includes, excuse the redundance, inlinePicture images. Floating images are not included in that collection, something we will add in future iterations of the API.
There is a workaround that I suggest you to do to check if there are floating images in the selection.
you can get and analyze the OOXML from the selection and find out of there are any floating images in the selection.
this code shows how to get the OOXML from the selection:
// Run a batch operation against the Word object model.
Word.run(function (context) {
// Queue a command to get the current selection and then
// create a proxy range object with the results.
var range = context.document.getSelection();
// Queue a commmand to get the OOXML of the current selection.
var ooxml = range.getOoxml();
// Synchronize the document state by executing the queued-up commands,
// and return a promise to indicate task completion.
return context.sync().then(function () {
console.log('The OOXML read from the document was: ' + ooxml.value);
});
}).catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
Once you have the OOXML you can actually get (with string search or XML editors) what's within in the of if look for something like this element, you will know there is a floating image there. you can also get the alt text and description as you can see. if so needed you can use that string replace the alt text properties you need and can write back the OOXML to update that floating image. its a bit painful but doable and hopefully we can ship the floating images collection soon! thanks and happy coding!!!
<w:drawing>
<wp:anchor allowOverlap="1" layoutInCell="1" locked="0" behindDoc="0" relativeHeight="251659264" simplePos="1" distR="114300" distL="114300" distB="0" distT="0">
<wp:simplePos y="3710305" x="1729105"/>
<wp:positionH relativeFrom="margin">
<wp:posOffset>1729105</wp:posOffset>
</wp:positionH>
<wp:positionV relativeFrom="margin">
<wp:posOffset>3710305</wp:posOffset>
</wp:positionV>
<wp:extent cx="2847975" cy="2133600"/>
<wp:effectExtent r="9525" b="0" t="0" l="0"/>
<wp:wrapSquare wrapText="bothSides"/>
<wp:docPr title="alt text sample" name="Picture 1" descr="alt test description!!" id="1"/>
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/>
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr name="stratus2.jpg" id="1"/>
<pic:cNvPicPr/>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rId4">
<a:extLst>
<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
<a14:useLocalDpi val="0" xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"/>
</a:ext>
</a:extLst>
</a:blip>
<a:stretch>
<a:fillRect/>
</a:stretch>
</pic:blipFill>
<pic:spPr>
<a:xfrm>
<a:off y="0" x="0"/>
<a:ext cx="2847975" cy="2133600"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</pic:spPr>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:anchor>
</w:drawing>
I want to use ngMap to add Google Maps to my app.
The demos are "static" in the sense that they have only hard coded HTML. I want my code to be "dynamic" in the sense that it will periodically ask a server to look in its database and return me a bunch of coordinates to plot, which will change with time. I hope that that is clear; if not, please ask for more detail.
I modified the ngmap markers demo to generate some random lat/long coordinates every two seconds (rather than going to my server, as my final app will). Please see the Plunk.
There are no errors in the console, and it seems that ngMap is trying to add my markers, as I see a lot of this sort of thing in the console ...
adding marker with options,
Object {ngRepeat: "myMarker in markers", position: O}
clickable: true
ngRepeat: "myMarker in markers"
position: O
A: 103.96749299999999
k: 1.387454
__proto__: O
visible: true
__proto__: Object
where K and A are the Lat/Long as I expect them to be.
BUT ... I don't see any markers on the map. What am I doing wrong?
[Update] An excellent answer, for which I gladly awarded a bounty afterwards. For anyone else reading this and wishing to use ngMap as #allenhwkim said in another stackoverflow question and, I think, on his blog, ngMap just creates the map for you & after that you manipulate it with the standard Google Maps API.
For instance, just before looping to add the markers, I declared
var bounds = new google.maps.LatLngBounds(); and in the loop, after adding the marker to the map, I bounds.extend(latlng); and, finally, after the loop, I
var centre = bounds.getCenter();
$scope.map.setCenter(centre);
I forked the answer and created a new Plunk to show this. Not the world's most useful functionality, but the point is just to show how to use $scope.map with the Google Maps API. Thanks again, Allen, for ngMap.
Answer is here
http://plnkr.co/edit/Widr0o?p=preview
Please remember that ngMap is not replacing Google Maps V3 API.
Let me know if you have further questions.
The following is code block of the controller.
// $scope.map .. this exists after the map is initialized
var markers = [];
for (var i=0; i<8 ; i++) {
markers[i] = new google.maps.Marker({
title: "Hi marker " + i
})
}
$scope.GenerateMapMarkers = function() {
$scope.date = Date(); // Just to show that we are updating
var numMarkers = Math.floor(Math.random() * 4) + 4; // betwween 4 & 8 of them
for (i = 0; i < numMarkers; i++) {
var lat = 1.280095 + (Math.random()/100);
var lng = 103.850949 + (Math.random()/100);
// You need to set markers according to google api instruction
// you don't need to learn ngMap, but you need to learn google map api v3
// https://developers.google.com/maps/documentation/javascript/marker
var latlng = new google.maps.LatLng(lat, lng);
markers[i].setPosition(latlng);
markers[i].setMap($scope.map)
}
$timeout(function() {
$scope.GenerateMapMarkers();
}, 2000); // update every 2 seconds
};
$scope.GenerateMapMarkers();
Why not do something like
<map zoom="2" center="[40.74, -74.18]">
<marker position="{{destination.position}}" ng-repeat="destination in destinations"></marker>
</map>
If you asking for ng-repeat that would work. And you would populate the destinations with a simple http call to your backend:
$http.get(url + '/destinations', config).success(function (data) {
if (data != null && data.total > 0) {
$scope.destinations = data.destinations;
} else {
$scope.destinations = []
}
});