Have Google maps center around geo-locs and zoom in appropriately - api

I would like to pass an x amount of geo-locations to the Google Maps API and have it centered around these locations and set the appropriate zoom level so all locations are visible on the map. I.e. show all the markers that are currently on the map.
Is this possible with what the Google Maps API offers by default or do I need to resolve to build this myself?

I used fitBounds (API V3) for each point:
Declare the variable.
var bounds = new google.maps.LatLngBounds();
Go through each marker with FOR loop
for (i = 0; i < markers.length; i++) {
var latlng = new google.maps.LatLng(markers[i].lat, markers[i].lng);
bounds.extend(latlng);
}
Finally call
map.fitBounds(bounds);

There are a number of ways of doing this but it is pretty easy if you are using the V2 API. See this post for an example, this group post or this post.

For V3 there's zoomToMarkers

Gray's Idea is great but does not work as is. I had to work out a hack for a zoomToMarkers API V3:
function zoomToMarkers(map, markers)
{
if(markers[0]) // make sure at least one marker is there
{
// Get LatLng of the first marker
var tempmark =markers[0].getPosition();
// LatLngBounds needs two LatLng objects to be constructed
var bounds = new google.maps.LatLngBounds(tempmark,tempmark);
// loop thru all markers and extend the LatLngBounds object
for (var i = 0; i < markers.length; i++)
{
bounds.extend(markers[i].getPosition());
}
// Set the map viewport
map.fitBounds(bounds);
}
}

Related

Semantic Tokens in MarkupString / MarkupContent

Is it possible to use MarkdownString/MarkupContent with code or pre with span to emulate semantic tokens in Hover? If so, is it possible to access the colors from the user's theme using only the CSS on the span elements? Ideally I would like to avoid using anything VSCode specific.
I saw https://github.com/microsoft/vscode/issues/97409 but there was no solution.
If you want to manually set colors for code you can try this:
// using your fileSelector
let disposable = vscode.languages.registerHoverProvider('plaintext', {
provideHover(document, position) {
const codeBlock = `<code><span style="color:#f00;background-color:#fff;">const</span> a = 12</code>`;
const markdown = new vscode.MarkdownString();
// markdown.appendCodeblock(codeBlock, "javascript");
markdown.appendMarkdown(codeBlock);
markdown.supportHtml = true;
markdown.isTrusted = true;
return new vscode.Hover(markdown, new vscode.Range(position, position));
}
});
<pre> also works, instead of <code>, but I think <code> looks better.

How to use THREE js TextureLoader() in React native?

I am trying to create a 3D model in React-Native using Three.js, for that I have to use an image for texture but TextureLoader() function using 'document' and 'canvas' object creation logic, which can't be used in react-native.
so, how can I use an image as texture in react-native using three.js ?
Short summary: the Textureloader didnt work because it required an imageloader which required the inaccesible DOM.
Apparantly there's a THREE.Texture function which i used like this:
let texture = new THREE.Texture(
url //URL = a base 64 JPEG string in this case
);
var img = new Image(128, 128);
img.src = url;
texture.normal = img;
As you can see i used an Image constructor, this is from React Native and is imported like this:
import { Image } from 'react-native';
In the react native documentation it will explain how it can be used, it supports base64 encoded JPEG.
and finally map the texture to the material:
material.map = texture;
Note: i havent tried to show the end result in my webglview yet, but in the element inspector it seems to show proper THREEjs objects.
(Note: this is not the answer)
EDIT: made the code a bit shorter and use DOMParser, still doesnt work because:
"image.addEventListener is not a function"
Which implies the image object which is created in this method doesnt seem to be able to be used in THREEjs,..
var DOMParser = require('react-native-html-parser').DOMParser;
var myDomParser = new DOMParser();
window.document = {};
window.document.createElementNS = (x,y) => {
if (y === "img") {
let doc = myDomParser.parseFromString("<html><head></head><body><img class='image' src=''></img></body></html>");
return doc.getElementsByAttribute("class", "image")[0];
}
}
Edit: be careful with this, because it also overrides the other createElemensNS variants in which they create canvas or other things.

Strava API - accurate longitude and latitude

Does anyone know a way to get the exact longitude and latitude for an activity from the strava api using a get request?
I'm trying to integrate the strava api with google maps and I'm trying to build an array with the appropriate long/lat locations, but the https://www.strava.com/api/v3/athlete/activities?per_page=100... request is only returning longitude and latitudes rounded off like: start_longitude: 2.6.
I've found a "hacky" way of retrieving the start coordinates by looping through results and then sending off another request within the loop, although this is sending WAY too many requests. - below is a snippet of my request:
// start request
$.get( "https://www.strava.com/api/v3/athlete/activities?per_page=100&access_token=ACCESSTOKEN", function (results) {
// loop through request
for (i = 0; i < results.length; i++) {
if(results[i].type === 'Run') {
// add an element to the array for each result
stravaComplete.push(true);
$.get( "https://www.strava.com/api/v3/activities/"+ results[i].id +"?per_page=5&access_token=ACCESSTOKEN", function (runs) {
if(typeof runs.segment_efforts[0] != "undefined"){
var runLatitude = runs.segment_efforts[0].segment.start_latitude;
var runLongitude = runs.segment_efforts[0].segment.start_longitude;
stravaActivityList.push({"lat": runLatitude, "lng": runLongitude});
}
// remove the element from the array
stravaComplete.pop();
// if all the elements have been removed from the array it means the request is complete
if(stravaComplete.length == 0) {
// reinitialize map
initMap(stravaActivityList);
}
});
}
}
});
Any guidance would be great. Thanks.
It's not clear if you need coordinates of start points only, or for the whole activity and what accuracy is required.
Response to query https://www.strava.com/api/v3/athlete/activities includes a field map => summary_polyline from which you should be able to extract coordinates of the whole (although simplified) activity. You can also use this polyline to display it in google maps.
If you, however, need even better accuracy you need to retrieve every activity and use map => summary_polyline or map => polyline fields.
To get full data streams should be used
Use summary_polyline[0] and summary_polyline[-1] (Ruby) instead of rounded values. See this code from Slava for an example.

Convert Feature Layer to an array of Polygons in ArcGIS JS?

Pretty straight forward: I am simply trying to get a feature layer
var floodLayer = new FeatureLayer("URL");
and convert it to a polygon array similar to:
var polygons = [];
for (var i = 0; i < floodLayer.graphics.length; i++) {
var polygons[i] = new Polygon({ "rings": floodLayer.graphics[i].rings, "spatialReference": floodLayer.graphics[i].spatialReference });
}
However, feature layers don't appear to have the appropriate properties to create polygons. Unless I am missing something?
rings and spatialReference are properties of geometry which is a property of your graphics. So you need to use floodLayer.graphics[i].geometry.rings instead of floodLayer.graphics[i].rings, for example.

Panning the map to certain extent javascript API

I want to limit map extent to the initial extent of the map and limit user from panning more than certain extent.
I tried following but nothing has changed:
map = new Map( "map" , {
basemap: "gray",
center: [-85.416, 49.000],
zoom : 6,
logo: false,
sliderStyle: "small"
});
dojo.connect(map, "onExtentChange", function (){
var initExtent = map.extent;
var extent = map.extent.getCenter();
if(initExtent.contains(extent)){}
else{map.setExtent(initExtent)}
});
Just to flesh out Simon's answer somewhat, and give an example. Ideally you need two variables at the same scope as map:
initExtent to store the boundary of your valid extent, and
validExtent to store the last valid extent found while panning, so that you can bounce back to it.
I've used the newer dojo.on event syntax as well for this example, it's probably a good idea to move to this as per the documentation's recommendation - I assume ESRI will discontinue the older style at some point.
var map;
var validExtent;
var initExtent;
[...]
require(['dojo/on'], function(on) {
on(map, 'pan', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
console.log('Outside bounds!');
} else {
console.log('Updated extent');
validExtent = evt.extent;
}
});
on(map, 'pan-end', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
map.setExtent(validExtent);
}
});
});
You can do the same with the zoom events, or use extent-change if you want to trap everything. Up to you.
It looks like your extent changed function is setting the initial extent variable to the maps current extent and then checking if that extent contains the current extents centre point - which of course it always will.
Instead, declare initExtent at the same scope of the map variable. Then, change the on load event to set this global scope variable rather than a local variable. In the extent changed function, don't update the value of initExtent, simply check the initExtent contains the entire of the current extent.
Alternatively you could compare each bound of the current extent to each bound of the initExtent, e.g. is initExtent.xmin < map.extent.xmin and if any are, create a new extent setting any exceeded bounds to the initExtent values.
The only problem is these techniques will allow the initExtent to be exceeded briefly, but will then snap the extent back once the extent changed function fires and catches up.
I originally posted this solution on gis.stackexchange in answer to this question: https://gis.stackexchange.com/a/199366
Here's a code sample from that post:
//This function limits the extent of the map to prevent users from scrolling
//far away from the initial extent.
function limitMapExtent(map) {
var initialExtent = map.extent;
map.on('extent-change', function(event) {
//If the map has moved to the point where it's center is
//outside the initial boundaries, then move it back to the
//edge where it moved out
var currentCenter = map.extent.getCenter();
if (!initialExtent.contains(currentCenter) &&
event.delta.x !== 0 && event.delta.y !== 0) {
var newCenter = map.extent.getCenter();
//check each side of the initial extent and if the
//current center is outside that extent,
//set the new center to be on the edge that it went out on
if (currentCenter.x < initialExtent.xmin) {
newCenter.x = initialExtent.xmin;
}
if (currentCenter.x > initialExtent.xmax) {
newCenter.x = initialExtent.xmax;
}
if (currentCenter.y < initialExtent.ymin) {
newCenter.y = initialExtent.ymin;
}
if (currentCenter.y > initialExtent.ymax) {
newCenter.y = initialExtent.ymax;
}
map.centerAt(newCenter);
}
});
}
And here's a working jsFiddle example: http://jsfiddle.net/sirhcybe/aL1p24xy/