See this DEMO
In the document, I saw the description of bounds parameter is:
Fit the map in the specified bounds. The expression must resolve to an
object having both northeast and southwest properties. Each of those
properties must have a latitude and a longitude properties
I set the bounds in scope:
$scope.bd = {
northeast: {
latitude: 51.219053,
longitude: 4.404418
},
southwest: {
latitude: -51.219053,
longitude: -4.404418
}
}
And used it in directive like this:
<ui-gmap-google-map bounds="bd" center="map.center" zoom="map.zoom" draggable="true" options="options"></ui-gmap-google-map>
But it seems that there is no effect.. the map is not fitted in my specified bounds.. Does that mean the bounds parameter is not working? And how to make the map to fit the specified bounds?
Why not using center and zoom instead of bounds ?
Anyway, I was doing some tests and as the center, zoom and bounds are in a whatch inside a directive, those are loaded async, and as the center and zoom are required the bounds are not efected.
Even setting the value after it didn't change ( don't know why )
http://plnkr.co/edit/YdyYIiVVgApA2tpm11Xn?p=preview
setTimeout(function(){
var map = $scope.instance.getGMap();
console.log(map);
console.log(map.getBounds());
$scope.bd = {
northeast: {
latitude: 51.219053,
longitude: 4.404418
},
southwest: {
latitude: -51.219053,
longitude: -4.404418
}
}
ne = new google.maps.LatLng($scope.bd.northeast.latitude, $scope.bd.northeast.longitude);
sw = new google.maps.LatLng($scope.bd.southwest.latitude, $scope.bd.southwest.longitude);
bounds = new google.maps.LatLngBounds(sw, ne);
map.fitBounds(bounds);
}, 2000);
Related
I've got a Map() in my code, don't think you need my code as it's literally just a Map() with the region set. But I was wondering how I can customize the showsUserLocation: True . I want it to display an SF Symbol icon.
Let me know if you need anything else.
Thanks.
Try this approach to display a SF Symbol at a desired location, works well for me.
import Foundation
import SwiftUI
import MapKit
import CoreLocation
struct ContentView: View {
var body: some View {
MapView()
}
}
struct MyLocation: Identifiable {
let id = UUID()
var name: String
var coordinate: CLLocationCoordinate2D
}
struct MapView: View {
#State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 35.661991, longitude: 139.762735), span: MKCoordinateSpan(latitudeDelta: 0.0925, longitudeDelta: 0.0925))
// simulated user location
#State var myLocations = [MyLocation(name: "tokyo", coordinate: CLLocationCoordinate2D(latitude: 35.661991, longitude: 139.762735))]
var body: some View {
Map(coordinateRegion: $region, interactionModes: .all,
showsUserLocation: true,
userTrackingMode: .constant(.follow),
annotationItems: myLocations) { myLoc in
MapAnnotation(coordinate: myLoc.coordinate) {
Image(systemName: "figure.wave").resizable() // <-- here
.frame(width: 33, height: 33)
.foregroundColor(.red)
}
}
}
}
I'm making a virtual tour using AFrame, with a <a-sky> for the 360° images, some <a-circle> for hotspots, and <a-text> below circles for indications.
My goal is to make texts always parallel to the screen. I already try the aframe-look-at-component on the camera, but it's not what I was looking for because they face a point instead of facing the screen.
So my next idea was to create an invisible cursor, and copy his rotation the the texts, but I'm not sure of this because I don't know if the cursor update his rotation or if it's only base on the cam rotation.
Anyway the main source of this problem was I don't know how to change the rotation of my text after creation, I tried mytext.object3D.rotation, mytext.setAttribute('rotation', newRotation), and also object3D.lookAt(), but either it didn't matter, or it wasn't what I was looking for.
What is the best way to achieve this ?
Here my hotspot component (which create the texts based on some props):
AFRAME.registerPrimitive('a-hotspot', {
defaultComponents: {
hotspot: {}
},
mappings: {
for: 'hotspot.for',
to: 'hotspot.to',
legend: 'hotspot.legend',
'legend-pos': 'hotspot.legend-pos',
'legend-rot': 'hotspot.legend-rot'
}
});
AFRAME.registerComponent('hotspot', {
schema: {
for: { type: 'string' },
to: { type: 'string' },
legend: { type: 'string' },
'legend-pos': { type: 'vec3', default: {x: 0, y: -0.5, z:0}},
'legend-rot': { type: 'number', default: 0 },
positioning: { type: 'boolean', default: false }
},
init: function () {
this.shiftIsPress = false
window.addEventListener('keydown', this.handleShiftDown.bind(this))
window.addEventListener('keyup', this.handleShiftUp.bind(this))
this.tour = document.querySelector('a-tour');
if (this.data.legend)
this.addText();
this.el.addEventListener('click', this.handleClick.bind(this));
},
// Creating the text, based on hotspots props
addText: function () {
var hotspot = this.el,
position = new THREE.Vector3(hotspot.object3D.position.x, hotspot.object3D.position.y, hotspot.object3D.position.z),
text = document.createElement('a-text'),
loadedScene = document.querySelector('a-tour').getAttribute('loadedScene')
position.x += this.data['legend-pos'].x
position.y += this.data['legend-pos'].y
position.z += this.data['legend-pos'].z
console.log(this.data['legend-rot'])
// Set text attributes
text.id = `text_${this.data.for}_to_${this.data.to}`
text.setAttribute('position', position)
text.setAttribute('color', '#BE0F34')
text.setAttribute('align', 'center')
text.setAttribute('value', this.data.legend)
text.setAttribute('for', this.data.for)
if (loadedScene && loadedScene !== this.data.for) text.setAttribute('visible', false)
// Insert text after hotspot
hotspot.parentNode.insertBefore(text, hotspot.nextSibling)
},
// This part is supposed to edit the rotation
// to always fit to my idea
tick: function () {
if (this.el.getAttribute('visible')) {
var cursorRotation = document.querySelector('a-cursor').object3D.getWorldRotation()
//document.querySelector(`#text_${this.data.for}_to_${this.data.to}`).object3D.lookAt(cursorRotation)
this.updateRotation(`#text_${this.data.for}_to_${this.data.to}`)
}
},
// This parts manage the click event.
// When shift is pressed while clicking on hotspot, it enable another component
// to stick a hotspot to the camera for help me to place it on the scene
// otherwise, it change the 360° image and enbable/disable hotspots.
handleShiftDown: function (e) {
if (e.keyCode === 16) this.shiftIsPress = true
},
handleShiftUp: function (e) {
if (e.keyCode === 16) this.shiftIsPress = false
},
handleClick: function (e) {
var target = 'target: #' + this.el.id
var tour = this.tour.components['tour']
if (this.shiftIsPress)
tour.el.setAttribute('hotspot-helper', target)
else
tour.loadSceneId(this.data.to, true);
}
});
I really don't know what to do..
EDIT: I found a part solution:
If I had geometry to my text (and material with alphaTest: 1 for hide it), setAttribute('rotation') work, and I base it on camera rotation. The problem is that after that, the camera is locked, don't understand why ^^
var cursorRotation = document.querySelector('a-camera').object3D.rotation
document.querySelector(`#text_${this.data.for}_to_${this.data.to}`).setAttribute('rotation', cursorRotation)
Thanks,
Navalex
I finally found the solution !
Instead of document.querySelector('a-camera').object3D.rotation, I used document.querySelector('a-camera').getAttribute('rotation') and it's work nice !
Be sure to check out the example here: https://stemkoski.github.io/A-Frame-Examples/sprites.html
The 'box' sign is always visible to user
I am creating a walkthrough for the interior of a building and am wondering how to draw a marker on a StreetViewPanorama. Maybe I'm missing something basic, but everything I have read indicates that you need a lat and lng to draw the marker.
Here is what I have:
var initPosPanoID, streetView;
function initPano() {
// Set StreetView provider.
var streetViewOptions = {
zoom: 0,
panoProvider: getCustomPanorama,
pano : "lobby",
addressControlOptions: {
position: google.maps.ControlPosition.BOTTOM_CENTER
}
};
// Create a StreetView object.
var streetViewDiv = document.getElementById('map');
streetView = new google.maps.StreetViewPanorama(streetViewDiv, streetViewOptions);
// Add links when it happens "links_change" event.
google.maps.event.addListener(streetView, "links_changed", createCustomLink);
google.maps.event.addListener(streetView, "pano_changed", function() {
var panoCell = document.getElementById('pano-cell');
panoCell.innerHTML = panorama.getPano();
});
}
function getCustomPanoramaTileUrl(panoID, zoom, tileX, tileY) {
// Return a pano image given the panoID.
return "images/he/" + panoID + '.jpg';
}
function getHeading(panoID) {
var heading;
switch(panoID) {
case "lobby":
heading = 0;
break;
case "secorner":
heading = 100;
break;
}
return heading;
}
function getCustomPanorama(panoID) {
// get a custom heading for the pano
var heading = getHeading(panoID);
var streetViewPanoramaData = {
links: [],
copyright: 'Imagery (c) HumanElement',
tiles: {
tileSize : new google.maps.Size(1024, 512),
worldSize : new google.maps.Size(1024, 512),
// The heading in degrees at the origin of the panorama
// tile set.
centerHeading : heading,
getTileUrl : getCustomPanoramaTileUrl
}
};
switch(panoID) {
case "lobby":
// Description of this point.
streetViewPanoramaData["location"] = {
pano: 'lobby',
description: "Human Element",
latLng: new google.maps.LatLng(42.282138, -83.751471)
};
return streetViewPanoramaData;
case "secorner":
streetViewPanoramaData["location"] = {
pano: 'secorner',
description: "SouthEast Corner",
latLng: new google.maps.LatLng(42.282078, -83.751413)
};
return streetViewPanoramaData;
}
}
function createCustomLink() {
var links = streetView.getLinks();
var panoID = streetView.getPano();
switch(panoID) {
case "lobby":
links.push({
description : "SouthEast Corner",
pano : "secorner",
heading : 280
});
break;
case "secorner":
links.push({
description : "HumanElement Lobby",
pano : "lobby",
heading : 90
});
break;
}
}
I would like to have different markers or touchpoints at different locations, but am not sure how to get them on there.
Trying to draw a standard marker does not work without the lat/lng.
I thought about trying to create it around a google.maps.Point thinking I might be able to use the x and y from my tiles, but couldn't seem to get that working.
The other options I see are related to google.maps.drawing.DrawingManager.
Does anyone have any advice on this?
Setting up the map this way helped: It creates the map and panorama separately and then sets the panorama into the map, rather than just having the panorama object by itself.
map = new google.maps.Map(document.getElementById('map'), {
center: position,
zoom: 10
});
// Create the panorama and set it into the map
panorama = new google.maps.StreetViewPanorama(
document.getElementById('map'), {
position: position,
pov: {
heading: 0,
pitch: -10
},
// Override the default panoId to outside the building to start
pano:'e_giRekRylYAAAQn7y2xAg'
});
map.setStreetView(panorama);
For placing markers on the map, I found an excellent plugin which creates points and then places elements on those points.
https://github.com/marmat/google-maps-api-addons/tree/master/panomarker
So far this is working very well. If you have an interior walkthrough, you should be able to toggle markers based on the PanoId. You can even add click listeners to open up dialogs.
I'm trying to create a pulse effect on a point on a AmCharts Map. In order to do this I need to insert HTML at a latitude and longitude point but can't work out how to do it through the api (http://docs.amcharts.com/3/javascriptmaps/)
Here is the effect I'm trying to achieve - http://kevinurrutia.tumblr.com/post/16411271583/creating-a-css3-pulsating-circle
Here is a jsfiddle of the map with the HTML and CSS http://jsfiddle.net/9cBXh/2/
// request #3275
var dataPoints = [{
latitude: '51.000000000000',
longitude: '9.000000000000',
type: 'bubble',
color: '#cc0000',
fixedSize: false,
alpha: 0.9,
height: 30,
width: 30,
centered: true,
id: 'test'
}];
AmCharts.ready(function() {
// create AmMap object
var map = new AmCharts.AmMap();
// set path to images
map.pathToImages = "http://www.ammap.com/lib/images/";
var dataProvider = {
mapVar: AmCharts.maps.worldLow,
getAreasFromMap:false,
images: dataPoints
};
// pass data provider to the map object
map.dataProvider = dataProvider;
map.areasSettings = {
autoZoom: true,
selectedColor: "#CC0000"
};
// write the map to container div
map.write("mapdiv");
});
The red dot is the bubble generated through the api. The blue dot and circle is the html I need to insert at the lat and long co-ordinates...somehow!
Any help would be appreciated.
Here's a complete working example of the AmCharts map with several pulsating HTML elements as map markers:
http://www.amcharts.com/demos/custom-html-elements-map-markers/
(You can view the source by clicking on the EDIT button)
The idea is very simple:
Trap "positionChanged" event. Go throiugh all of the "images" in the map's dataProvider, create HTML elements for each of those, then position them directly over the map by using API functions that resolve longitude/latitude coordinates to screen top/left coordinates:
// add events to recalculate map position when the map is moved or zoomed
map.addListener("positionChanged", updateCustomMarkers);
// this function will take current images on the map and create HTML elements for them
function updateCustomMarkers (event) {
// get map object
var map = event.chart;
// go through all of the images
for( var x in map.dataProvider.images) {
// get MapImage object
var image = map.dataProvider.images[x];
// check if it has corresponding HTML element
if ('undefined' == typeof image.externalElement)
image.externalElement = createCustomMarker(image);
// reposition the element accoridng to coordinates
image.externalElement.style.top = map.latitudeToY(image.latitude) + 'px';
image.externalElement.style.left = map.longitudeToX(image.longitude) + 'px';
}
}
// this function creates and returns a new marker element
function createCustomMarker(image) {
// create holder
var holder = document.createElement('div');
holder.className = 'map-marker';
holder.title = image.title;
holder.style.position = 'absolute';
// create dot
var dot = document.createElement('div');
dot.className = 'dot';
holder.appendChild(dot);
// create pulse
var pulse = document.createElement('div');
pulse.className = 'pulse';
holder.appendChild(pulse);
// append the marker to the map container
image.chart.chartDiv.appendChild(holder);
return holder;
}
I draw a 3-mile-radius circle at a specified location but the zoom level shows the entire USA and the Pacific and Atlantic Oceans. If I zoom in manually via the UI scale widget, the circle is where it should be and is the correct size. I thought fitBounds() zoomed in automatically? If an explicit call to setZoom() is required, how to calculate the correct zoom-level to encompass the entire circle without showing too much of the area outside the circle?
function setInitialMapFocusByZipcode(zipcode, desiredRadius)
{
geocoder.geocode(
{ 'address': zipcode }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
usmap.setCenter(results[0].geometry.location);
var circ = new google.maps.Circle({
map: usmap,
fillOpacity: 0.25
});
circ.setRadius(desiredRadius * 1609.344); // desiredRadius=3 in testing
circ.setCenter(results[0].geometry.location);
usmap.fitBounds(circ.getBounds());
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}