Mapbox javascript : to animate marker on a polyline (points) - javascript

I need to add a marker that moves on the points (polyline), I tried with https://docs.mapbox.com/mapbox-gl-js/example/animate-point-along-route but it's for a line, I have many points.. I don't know how to do..I tried this Animate an icon by using serious of Lat/lon Array - Mapbox js but it doesn't work.. thanks for your help !
var marker = new mapboxgl.Marker({
color: '#EC0868',
className: 'marker'
})
.setLngLat([6.161062, 45.36362])
.addTo(map);
var coords = [
[6.157903, 45.361839],
[6.15835, 45.361932],
[6.161408,45.3634445],
[6.161558, 45.363508],
[6.161307, 45.363462],
[6.1610, 45.363570],
[6.161057, 45.36362]
];
map.on('load', function () {
fitMap(map, coords);
displayJourney(map, coords);
});
function fitMap(map, coords) {
var bounds = coords.reduce(function (bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coords[0], coords[0]));
map.fitBounds(bounds, {
padding: 30
});
}
function displayJourney(map, coords) {
map.addLayer({
"id": "journey",
"type": "line",
"source": {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": coords
}
}
},
"paint": {
"line-color": "#888",
"line-width": 4,
'line-dasharray': [2, 2]
}
});
}

I combined Emma's and Moritz's code below;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Animate a point along a route</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<style>
.overlay {
position: absolute;
top: 10px;
left: 10px;
}
.overlay button {
font: 600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
background-color: #3386c0;
color: #fff;
display: inline-block;
margin: 0;
padding: 10px 20px;
border: none;
cursor: pointer;
border-radius: 3px;
}
.overlay button:hover {
background-color: #4ea0da;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/#turf/turf#5/turf.min.js"></script>
<div id="map"></div>
<div class="overlay">
<button id="replay">Replay</button>
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieW9jaGkiLCJhIjoiY2tjZThvdWExMDV2dDJxcDgxZzBwbzlxYSJ9.M0yRA6SXDMRgXzXGuYnvsg';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [6.161062, 45.36362],
zoom: 9
});
var coords = [
[6.157903, 45.361839],
[6.15835, 45.361932],
[6.161408,45.3634445],
[6.161558, 45.363508],
[6.161307, 45.363462],
[6.1610, 45.363570],
[6.161057, 45.36362]
];
var route = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': coords
}
}
]
};
var marker = new mapboxgl.Marker({
color: '#EC0868',
className: 'marker'});
// Calculate the distance in kilometers between route start/end point.
var lineDistance = turf.length(route.features[0]);
var arc = [];
// Number of steps to use in the arc and animation, more steps means
// a smoother arc and animation, but too many steps will result in a
// low frame rate
var steps = 500;
// Draw an arc between the `origin` & `destination` of the two points
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
var segment = turf.along(route.features[0], i);
arc.push(segment.geometry.coordinates);
}
// Update the route with calculated arc coordinates
route.features[0].geometry.coordinates = arc;
// Used to increment the value of the point measurement against the route.
var counter = 0;
map.on('load', function () {
// Add a source and layer displaying a point which will be animated in a circle.
map.addSource('route', {
'type': 'geojson',
'data': route
});
map.addLayer({
'id': 'route',
'source': 'route',
'type': 'line',
'paint': {
'line-width': 2,
'line-color': '#007cbf'
}
});
marker.setLngLat(route.features[0].geometry.coordinates[0]).addTo(map);
fitMap(map, coords);
function animate() {
// Update point geometry to a new position based on counter denoting
// the index to access the arc
marker.setLngLat(route.features[0].geometry.coordinates[counter]);
counter = counter + 1;
// Request the next frame of animation as long as the end has not been reached
if (counter < steps) {
requestAnimationFrame(animate);
}
}
document
.getElementById('replay')
.addEventListener('click', function () {
// Set the coordinates of the original point back to origin
marker.setLngLat(route.features[0].geometry.coordinates[0])
// Reset the counter
counter = 0;
// Restart the animation
animate(counter);
});
// Start the animation
animate(counter);
});
function fitMap(map, coords) {
var bounds = coords.reduce(function (bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coords[0], coords[0]));
map.fitBounds(bounds, {
padding: 30
});
}
https://codepen.io/OttyLab/pen/GRjBjwq

Hi Emma you can still use the approach. It also works for multiple coordinates given. Please see my example below, which does it for 3 coordinates. (1 coordinate pair extra) You can add as many additional "waypoints" as you like:
(to make it work, replace "YOUR ACCCESS TOKEN" )
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Animate a point along a route</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<style>
.overlay {
position: absolute;
top: 10px;
left: 10px;
}
.overlay button {
font: 600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
background-color: #3386c0;
color: #fff;
display: inline-block;
margin: 0;
padding: 10px 20px;
border: none;
cursor: pointer;
border-radius: 3px;
}
.overlay button:hover {
background-color: #4ea0da;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/#turf/turf#5/turf.min.js"></script>
<div id="map"></div>
<div class="overlay">
<button id="replay">Replay</button>
</div>
<script>
mapboxgl.accessToken = '<YOUR ACCESS TOKEN>';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-96, 37.8],
zoom: 3
});
// San Francisco
var origin = [-122.414, 37.776];
var waypoint1 = [-100.032, 38.913];
// Washington DC
var destination = [-77.032, 38.913];
// A simple line from origin to destination.
var route = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': [origin, waypoint1, destination] // here you can add the additional waypoints
}
}
]
};
// A single point that animates along the route.
// Coordinates are initially set to origin.
var point = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Point',
'coordinates': origin
}
}
]
};
// Calculate the distance in kilometers between route start/end point.
var lineDistance = turf.length(route.features[0]);
var arc = [];
// Number of steps to use in the arc and animation, more steps means
// a smoother arc and animation, but too many steps will result in a
// low frame rate
var steps = 500;
// Draw an arc between the `origin` & `destination` of the two points
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
var segment = turf.along(route.features[0], i);
arc.push(segment.geometry.coordinates);
}
// Update the route with calculated arc coordinates
route.features[0].geometry.coordinates = arc;
// Used to increment the value of the point measurement against the route.
var counter = 0;
map.on('load', function () {
// Add a source and layer displaying a point which will be animated in a circle.
map.addSource('route', {
'type': 'geojson',
'data': route
});
map.addSource('point', {
'type': 'geojson',
'data': point
});
map.addLayer({
'id': 'route',
'source': 'route',
'type': 'line',
'paint': {
'line-width': 2,
'line-color': '#007cbf'
}
});
map.addLayer({
'id': 'point',
'source': 'point',
'type': 'symbol',
'layout': {
'icon-image': 'airport-15',
'icon-rotate': ['get', 'bearing'],
'icon-rotation-alignment': 'map',
'icon-allow-overlap': true,
'icon-ignore-placement': true
}
});
function animate() {
var start =
route.features[0].geometry.coordinates[
counter >= steps ? counter - 1 : counter
];
var end =
route.features[0].geometry.coordinates[
counter >= steps ? counter : counter + 1
];
if (!start || !end) return;
// Update point geometry to a new position based on counter denoting
// the index to access the arc
point.features[0].geometry.coordinates =
route.features[0].geometry.coordinates[counter];
// Calculate the bearing to ensure the icon is rotated to match the route arc
// The bearing is calculated between the current point and the next point, except
// at the end of the arc, which uses the previous point and the current point
point.features[0].properties.bearing = turf.bearing(
turf.point(start),
turf.point(end)
);
// Update the source with this new data
map.getSource('point').setData(point);
// Request the next frame of animation as long as the end has not been reached
if (counter < steps) {
requestAnimationFrame(animate);
}
counter = counter + 1;
}
document
.getElementById('replay')
.addEventListener('click', function () {
// Set the coordinates of the original point back to origin
point.features[0].geometry.coordinates = origin;
// Update the source layer
map.getSource('point').setData(point);
// Reset the counter
counter = 0;
// Restart the animation
animate(counter);
});
// Start the animation
animate(counter);
});
</script>
</body>
</html>
Of course you can also create a list of coordinates, and pass this list to the geoJson route object.

Related

Keep Getting this.callInitHooks error (Leaflet)

I'm trying to add markers and a search bar to my leaflet choropleth map. However, I keep running into an error that tells me: Uncaught TypeError: this.callInitHooks is not a function. It comes from my leaflet.js file, and am unsure how to fix it. Most of my error seems to come from the leaflet links I've copied into my body before my script, or because of me trying to add a search bar or markets onto my map. I pasted my code below:
<html>
<head>
<title>How to make a choropleth map with Leaflet.js</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.0/dist/leaflet.css" />
<link rel="stylesheet" href="leaflet-search.css" />
<script src="censustracts.js"></script>
<style type="text/css">
html, body, #map{
height: 100%;
padding: 0;
margin: 0;
}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255,255,255,0.8);
box-shadow: 0 0 15px rgba(0,0,0,0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
.legend {
line-height: 18px;
color: #555;
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.7;
}
</style>
</head>
<body>
<div id="map"></map>
<script src="https://unpkg.com/leaflet#1.3.0/dist/leaflet.js"></script>
<script src="leaflet-search.js"></script>
<script type="text/javascript">
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {attribution: 'OSM'})
.addTo(map);
L.geoJson(statesData).addTo(map);
L.geoJson(statesData).addTo(map);
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
fillColor: getColor(feature.properties.density),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
L.geoJson(statesData, {style: style}).addTo(map);
///Functionality
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
info.update(layer.feature.properties);
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
//Add info
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};
// method that we will use to update the control based on feature properties passed
info.update = function (props) {
this._div.innerHTML = '<h4>US Population Density</h4>' + (props ?
'<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
: 'Hover over a state');
};
info.addTo(map);
//Add Legend
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 10, 20, 50, 100, 200, 500, 1000],
labels = [];
// loop through our density intervals and generate a label with a colored square for each interval
for (var i = 0; i < grades.length; i++) {
div.innerHTML +=
'<i style="background:' + getColor(grades[i] + 1) + '"></i> ' +
grades[i] + (grades[i + 1] ? '–' + grades[i + 1] + '<br>' : '+');
}
return div;
};
legend.addTo(map);
///Bind Popups
var data = [
{"loc":[32,-86], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.807149,13.162994], "title":"blue"},
{"loc":[41.507149,13.172994], "title":"chocolate"},
{"loc":[41.847149,14.132994], "title":"coral"},
{"loc":[41.219190,13.062145], "title":"cyan"},
{"loc":[41.344190,13.242145], "title":"darkblue"},
{"loc":[41.679190,13.122145], "title":"Darkred"},
{"loc":[41.329190,13.192145], "title":"Darkgray"},
{"loc":[41.379290,13.122545], "title":"dodgerblue"},
{"loc":[41.409190,13.362145], "title":"gray"},
{"loc":[41.794008,12.583884], "title":"green"},
{"loc":[41.805008,12.982884], "title":"greenyellow"},
{"loc":[41.536175,13.273590], "title":"red"},
{"loc":[41.516175,13.373590], "title":"rosybrown"},
{"loc":[41.506175,13.273590], "title":"royalblue"},
{"loc":[41.836175,13.673590], "title":"salmon"},
{"loc":[41.796175,13.570590], "title":"seagreen"},
{"loc":[41.436175,13.573590], "title":"seashell"},
{"loc":[41.336175,13.973590], "title":"silver"},
{"loc":[41.236175,13.273590], "title":"skyblue"},
{"loc":[41.546175,13.473590], "title":"yellow"},
{"loc":[41.239190,13.032145], "title":"white"}
];
var markersLayer = new L.LayerGroup(); //layer contain searched elements
map.addLayer(markersLayer);
var controlSearch = L.Control.Search({
position:'topright',
layer: markersLayer,
initial: false,
zoom: 12,
marker: false
});
map.addControl( controlSearch );
for(i in data) {
var title = data[i].title, //value searched
loc = data[i].loc, //position found
marker = new L.Marker(new L.latLng(loc), {title: title} );//se property searched
marker.bindPopup('title: '+ title );
markersLayer.addLayer(marker);
}
</script>
</body>
</html>
Don't use new with lowercase function:
marker = new L.Marker(new L.latLng(loc), {title: title} );
Use new L.LatLng(loc) or L.latLng(loc) without new

Mapbox GL - highlight features and queryRenderedFeatures() while allowing basemap style change

I need to be able to highlight features in a bounding box using Mapbox GL as shown in this example. My map also needs to have the ability to change the style layer, e.g. changing the base style from mapbox://styles/mapbox/light-v10 to mapbox://styles/mapbox/satellite-v9. This has been challenging because Mapbox GL does not natively support the concept of "basemaps" like, e.g. leaflet does.
My solution, after much searching (I believe I eventually followed a workaround posted in a github issue) involved:
Using map.on('style.load') instead of map.on('load') as shown in the example (I believe map.on('style.load') is not part of their public API, but I could be wrong) and,
Iterating through an array of sources/layers (see the vectorTileLayers variable in the code below) to add vector tiles layers to the map every time a new style is loaded.
This works brilliantly for me in some ways - I'm able to add an arbitrary number of vector tile sources to the array, and they are all added back to the map if the base style is changed. However, I am unable to add a query feature following the example provided by Mapbox if the sources/layers are added to the map in an array and iterated through as shown below. The bounding feature works, but when it is drawn, and released, I see the error show by running the snippet below.
This is a simplified version my actual problem that will allow others to run and manipulate the code. In reality, I'm adding my own vector tile layers (stored in the vectorTileLayers array, which works without issue. When I try and add another layer with the same source and different styling, as shown in the example, I'm unable to actually query the desired layer. Any help would be greatly appreciated. Just FYI - the toggleable layers buttons are not showing up in this snippet, but it's not critical to solve the problem.
mapboxgl.accessToken = 'pk.eyJ1IjoiamFtZXljc21pdGgiLCJhIjoiY2p4NTRzdTczMDA1dzRhbXBzdmFpZXV6eCJ9.-k7Um-xmYy4xhNDN6kDvpg';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
center: [-98, 38.88],
minZoom: 2,
zoom: 3
});
var vectorTileLayers = [{
source: {
type: 'vector',
url: 'mapbox://mapbox.82pkq93d'
},
layer: {
id: 'counties',
type: 'fill',
source: 'counties',
'source-layer': 'original',
paint: {
'fill-outline-color': 'rgba(0,0,0,0.1)',
'fill-color': 'rgba(0,0,0,0.1)'
},
}
},
{
source: {
type: 'vector',
url: 'mapbox://mapbox.82pkq93d'
},
layer: {
id: 'counties-highlighted',
type: 'fill',
source: 'counties',
'source-layer': 'original',
paint: {
'fill-outline-color': '#484896',
'fill-color': '#6e599f',
'fill-opacity': 0.75
},
filter: ['in', 'FIPS', '']
}
}
]
map.on('style.load', function() {
for (var i = 0; i < vectorTileLayers.length; i++) {
var tileLayer = vectorTileLayers[i];
map.addSource(tileLayer.layer.source, tileLayer.source);
map.addLayer(tileLayer.layer);
}
var layerList = document.getElementById('basemapmenu');
var inputs = layerList.getElementsByTagName('input');
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/mapbox/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
});
// Disable default box zooming.
map.boxZoom.disable();
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false
});
var canvas = map.getCanvasContainer();
var start;
var current;
var box;
canvas.addEventListener('mousedown', mouseDown, true);
// Return the xy coordinates of the mouse position
function mousePos(e) {
var rect = canvas.getBoundingClientRect();
return new mapboxgl.Point(
e.clientX - rect.left - canvas.clientLeft,
e.clientY - rect.top - canvas.clientTop
);
}
function mouseDown(e) {
// Continue the rest of the function if the shiftkey is pressed.
if (!(e.shiftKey && e.button === 0)) return;
// Disable default drag zooming when the shift key is held down.
map.dragPan.disable();
// Call functions for the following events
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
document.addEventListener('keydown', onKeyDown);
// Capture the first xy coordinates
start = mousePos(e);
}
function onMouseMove(e) {
// Capture the ongoing xy coordinates
current = mousePos(e);
// Append the box element if it doesnt exist
if (!box) {
box = document.createElement('div');
box.classList.add('boxdraw');
canvas.appendChild(box);
}
var minX = Math.min(start.x, current.x),
maxX = Math.max(start.x, current.x),
minY = Math.min(start.y, current.y),
maxY = Math.max(start.y, current.y);
// Adjust width and xy position of the box element ongoing
var pos = 'translate(' + minX + 'px,' + minY + 'px)';
box.style.transform = pos;
box.style.WebkitTransform = pos;
box.style.width = maxX - minX + 'px';
box.style.height = maxY - minY + 'px';
}
function onMouseUp(e) {
// Capture xy coordinates
finish([start, mousePos(e)]);
}
function onKeyDown(e) {
// If the ESC key is pressed
if (e.keyCode === 27) finish();
}
function finish(bbox) {
// Remove these events now that finish has been called.
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('keydown', onKeyDown);
document.removeEventListener('mouseup', onMouseUp);
if (box) {
box.parentNode.removeChild(box);
box = null;
}
// If bbox exists. use this value as the argument for `queryRenderedFeatures`
if (bbox) {
var features = map.queryRenderedFeatures(bbox, {
layers: ['counties']
});
if (features.length >= 1000) {
return window.alert('Select a smaller number of features');
}
// Run through the selected features and set a filter
// to match features with unique FIPS codes to activate
// the `counties-highlighted` layer.
var filter = features.reduce(
function(memo, feature) {
memo.push(feature.properties.FIPS);
return memo;
},
['in', 'FIPS']
);
map.setFilter('counties-highlighted', filter);
}
map.dragPan.enable();
}
map.on('mousemove', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['counties-highlighted']
});
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = features.length ? 'pointer' : '';
if (!features.length) {
popup.remove();
return;
}
var feature = features[0];
popup
.setLngLat(e.lngLat)
.setText(feature.properties.COUNTY)
.addTo(map);
});
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#basemapmenu {
position: absolute;
display: inline-block;
background-color: transparent;
bottom: 0;
left: 0;
margin-left: 10px;
margin-bottom: 40px;
}
.boxdraw {
background: rgba(56, 135, 190, 0.1);
border: 2px solid #3887be;
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
}
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet"/>
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<div id="map"></div>
<div id='basemapmenu'>
<input id='light-v10' class='btn btn-outline-primary' type='button' name='rtoggle' value='Light' checked='checked'>
<input id='dark-v10' class='btn btn-outline-primary' type='button' name='rtoggle' value='Dark'>
<input id='satellite-v9' class='btn btn-outline-primary' type='button' name='rtoggle' value='Satellite'>
</div>
I ran you code locally and found the problem!
You are trying to add same source twice and mapbox was giving you error for that, if you check your Console:
Problem: There can be only one source with one ID on Map
Error: There is already a source with this ID
After first loop execute successfully. On second iteration, it fails to add same source twice, code breaks here and doesn't continue further. Hence doesn't add second layer(therefore no functionality works thereafter!)
Fix:(Added a small check to not add same source if already added)
map.on('style.load', function () {
for (var i = 0; i < vectorTileLayers.length; i++) {
var tileLayer = vectorTileLayers[i];
if (!map.getSource(tileLayer.layer.source,)) //FIX
map.addSource(tileLayer.layer.source, tileLayer.source);
map.addLayer(tileLayer.layer);
}
var layerList = document.getElementById('basemapmenu');
var inputs = layerList.getElementsByTagName('input');
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/mapbox/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
});
I can see the Code is working fine:
Hope this will fix the problem.
I'll leave the above answer from Dolly as accepted because it answers my original question exactly. Unforunately, it didn't exactly solve my actual problem. After some additional fiddling, I wanted to post a fully functional version for reference in case people come across this looking for a solution to adding toggleable "basemap" layers in Mapbox GL with or without user interactivity options like this one.
The solution above does not work after toggling between basemap layers. The vector tile layers are not reloaded properly. The solution below seems to do the trick. It uses map.on('styledata' ...) rather than map.on('style.load' ...), which seems to allow for loading layers by the more conventional method of first calling map.addSource() followed by map.addLayer(). You can load a single source, and then an arbitrary number of layers pointing to that source. So in my "real world" example, I load 3 sources, and 5 layers from those sources.
(FYI - for some reason the built-in snippet tool from stack overflow isn't rendering the basemap buttons. If you copy the code exactly into JS fiddle or codepen it will work)
I hope this helps future humans - it seems like lots of people have had problems with managing Mapbox styles with custom layers on top. I certainly have.
mapboxgl.accessToken =
"pk.eyJ1IjoiamFtZXljc21pdGgiLCJhIjoiY2p4NTRzdTczMDA1dzRhbXBzdmFpZXV6eCJ9.-k7Um-xmYy4xhNDN6kDvpg";
var map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/light-v10",
center: [-98, 38.88],
minZoom: 2,
zoom: 3
});
map.on("styledata", function() {
map.addSource("counties", {
type: "vector",
url: "mapbox://mapbox.82pkq93d"
});
map.addLayer({
id: "counties",
type: "fill",
source: "counties",
"source-layer": "original",
paint: {
"fill-outline-color": "rgba(0,0,0,0.1)",
"fill-color": "rgba(0,0,0,0.1)"
}
});
map.addLayer({
id: "counties-highlighted",
type: "fill",
source: "counties",
"source-layer": "original",
paint: {
"fill-outline-color": "#484896",
"fill-color": "#6e599f",
"fill-opacity": 0.75
},
filter: ["in", "FIPS", ""]
});
var layerList = document.getElementById("basemapmenu");
var inputs = layerList.getElementsByTagName("input");
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle("mapbox://styles/mapbox/" + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
});
// Disable default box zooming.
map.boxZoom.disable();
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false
});
var canvas = map.getCanvasContainer();
var start;
var current;
var box;
canvas.addEventListener("mousedown", mouseDown, true);
// Return the xy coordinates of the mouse position
function mousePos(e) {
var rect = canvas.getBoundingClientRect();
return new mapboxgl.Point(
e.clientX - rect.left - canvas.clientLeft,
e.clientY - rect.top - canvas.clientTop
);
}
function mouseDown(e) {
// Continue the rest of the function if the shiftkey is pressed.
if (!(e.shiftKey && e.button === 0)) return;
// Disable default drag zooming when the shift key is held down.
map.dragPan.disable();
// Call functions for the following events
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
document.addEventListener("keydown", onKeyDown);
// Capture the first xy coordinates
start = mousePos(e);
}
function onMouseMove(e) {
// Capture the ongoing xy coordinates
current = mousePos(e);
// Append the box element if it doesnt exist
if (!box) {
box = document.createElement("div");
box.classList.add("boxdraw");
canvas.appendChild(box);
}
var minX = Math.min(start.x, current.x),
maxX = Math.max(start.x, current.x),
minY = Math.min(start.y, current.y),
maxY = Math.max(start.y, current.y);
// Adjust width and xy position of the box element ongoing
var pos = "translate(" + minX + "px," + minY + "px)";
box.style.transform = pos;
box.style.WebkitTransform = pos;
box.style.width = maxX - minX + "px";
box.style.height = maxY - minY + "px";
}
function onMouseUp(e) {
// Capture xy coordinates
finish([start, mousePos(e)]);
}
function onKeyDown(e) {
// If the ESC key is pressed
if (e.keyCode === 27) finish();
}
function finish(bbox) {
// Remove these events now that finish has been called.
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("keydown", onKeyDown);
document.removeEventListener("mouseup", onMouseUp);
if (box) {
box.parentNode.removeChild(box);
box = null;
}
// If bbox exists. use this value as the argument for `queryRenderedFeatures`
if (bbox) {
var features = map.queryRenderedFeatures(bbox, {
layers: ["counties"]
});
if (features.length >= 1000) {
return window.alert("Select a smaller number of features");
}
// Run through the selected features and set a filter
// to match features with unique FIPS codes to activate
// the `counties-highlighted` layer.
var filter = features.reduce(
function(memo, feature) {
memo.push(feature.properties.FIPS);
return memo;
}, ["in", "FIPS"]
);
map.setFilter("counties-highlighted", filter);
}
map.dragPan.enable();
}
map.on("mousemove", function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ["counties-highlighted"]
});
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = features.length ? "pointer" : "";
if (!features.length) {
popup.remove();
return;
}
var feature = features[0];
popup.setLngLat(e.lngLat).setText(feature.properties.COUNTY).addTo(map);
});
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#basemapmenu {
position: absolute;
display: inline-block;
background-color: transparent;
bottom: 0;
left: 0;
margin-left: 10px;
margin-bottom: 40px;
}
.boxdraw {
background: rgba(56, 135, 190, 0.1);
border: 2px solid #3887be;
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
}
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<div id="map"></div>
<div id='basemapmenu'>
<input id='light-v10' class='btn btn-outline-primary' type='button' name='rtoggle' value='Light' checked='checked'>
<input id='dark-v10' class='btn btn-outline-primary' type='button' name='rtoggle' value='Dark'>
<input id='satellite-v9' class='btn btn-outline-primary' type='button' name='rtoggle' value='Satellite'>
</div>

How to change position of the Earth in WebGL Earth

I am using this webgl earth for the project, but I can't seem to find a way to change the position of the planet on the canvas. My desired goal was to put the planet on the bottom of the page, but I can't find a way around it. I am providing the simple working demo for the issue. Thank you in advance.
function initialize() {
var options = {
// sky: true,
atmosphere: true,
zooming: false,
};
var earth = new WE.map('earth_div', options);
WE.tileLayer('https://webglearth.github.io/webglearth2-offline/{z}/{x}/{y}.jpg', {
tileSize: 256,
tms: true
}).addTo(earth);
// Start a simple rotation animation
var before = null;
requestAnimationFrame(function animate(now) {
var c = earth.getPosition();
var elapsed = before ? now - before : 0;
before = now;
earth.setCenter([c[0], c[1] + 0.1 * (elapsed / 30)]);
requestAnimationFrame(animate);
});
var marker = WE.marker([51.5, -0.09]).addTo(earth);
marker.bindPopup("<b>Hello world!</b><br>I am a popup.<br /><span style='font-size:10px;color:#999'>Tip: Another popup is hidden in Cairo..</span>", {
maxWidth: 150,
closeButton: true
}).openPopup();
var marker2 = WE.marker([30.058056, 31.228889]).addTo(earth);
marker2.bindPopup("<b>Cairo</b><br>Yay, you found me!", {
maxWidth: 120,
closeButton: false
});
var markerCustom = WE.marker([50, -9], '/img/logo-webglearth-white-100.png', 100, 24).addTo(earth);
// earth.setView([51.505, 0], 2.5);
}
html,
body {
padding: 0;
margin: 0;
background-color: white;
font-family: 'MyWebFont';
overflow: hidden;
}
#earth_div {
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute !important;
}
<script src="http://www.webglearth.com/v2/api.js"></script>
<body onload="initialize()">
<div id="earth_div">
</div>
The last line of your code. Sets camera to the given latitude / longitude position. Leaflet's LatLng is supported. ie:
earth.setView([51.505, 0], 6);

get coordinates of drawn feature in OpenLayers

I'm trying to create an online map using OpenLayers 3.
I'm brand new to using OpenLayers, and all I'm trying to do is to get the coordinates of the points, lines, polygons that I drew on the map. I'm aware that there is a featuresadded parameter available, but I'm not able to implement it correctly.
Can anybody point me in the right direction how to get the coordinates of a drawn feature (either in an alert() or console.log)?
Thanks a ton!!
here's my code:
<html>
<head>
<script src="http://openlayers.org/en/v3.3.0/build/ol.js" type="text/javascript"></script>
<link rel="stylesheet" href="ol.css" type="text/css">
<style type="text/css">
body {
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: small;
}
#map {
clear: both;
position: relative;
border: 1px solid black;
}
#wrapper {
width: 337px;
height: 50px;
}
#location {
float: right;
font-family: Arial, Verdana, sans-serif;
font-size: 12px;
color: #483D8B;
background-color: white;
}
#nodelist{
font-family: Arial, Verdana, sans-serif;
font-size: 14px;
color: #000000;
font-style: normal;
background-color: white;
}
</style>
<script type="text/javascript">
var map;
var draw;
var transformed_coordinate;
var vector;
function init() {
var view = new ol.View({
center: ol.proj.transform([13.1929, 55.718],'EPSG:4326', 'EPSG:3857'),
zoom: 12
});
var myZoom = new ol.control.Zoom();
var myZoomSlider = new ol.control.ZoomSlider();
var zoomToExtentControl = new ol.control.ZoomToExtent({
extent: [1453297.22,7490484.81,1483872.03,7513415.91]
});
var myScaleLine = new ol.control.ScaleLine()
var neighborhood = new ol.source.ImageWMS({
url: 'http://localhost:8090/geoserver/project/wms',
params: {'LAYERS': 'project:Neighborhood'}
});
var roads = new ol.source.ImageWMS({
url: 'http://localhost:8090/geoserver/project/wms',
params: {'LAYERS': 'project:Roads_all'}
});
var source = new ol.source.Vector({wrapX: false});
vector = new ol.layer.Vector({
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(0, 255, 0, 0.5)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 2
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#ffcc33'
})
})
})
});
var layers = [
new ol.layer.Image({
source: neighborhood
}),
new ol.layer.Image({
source: roads
}),
vector
]
map = new ol.Map({
layers: layers,
target: 'map',
view: view
});
map.addControl(myZoom);
map.addControl(myZoomSlider);
map.addControl(zoomToExtentControl);
map.addControl(myScaleLine);
map.on('singleclick', function(evt){
var coord = evt.coordinate;
transformed_coordinate = ol.proj.transform(coord, "EPSG:3857", "EPSG:4326");
//console.log(transformed_coordinate);
})
function onFeaturesAdded(event){
var bounds = event.features[0].geometry.getBounds();
var answer = "bottom: " + bounds.bottom + "\n";
answer += "left: " + bounds.left + "\n";
answer += "right: " + bounds.right + "\n";
answer += "top: " + bounds.top + "\n";
alert(answer);
}
var typeSelect = document.getElementById('type');
function addInteraction() {
var value = typeSelect.value;
if (value !== 'None') {
var geometryFunction, maxPoints;
if (value === 'Square') {
value = 'Circle';
geometryFunction = ol.interaction.Draw.createRegularPolygon(4);
} else if (value === 'Box') {
value = 'LineString';
maxPoints = 2;
geometryFunction = function(coordinates, geometry) {
if (!geometry) {
geometry = new ol.geom.Polygon(null);
}
var start = coordinates[0];
var end = coordinates[1];
geometry.setCoordinates([
[start, [start[0], end[1]], end, [end[0], start[1]], start]
]);
return geometry;
};
}
draw = new ol.interaction.Draw({
source: source,
type: /** #type {ol.geom.GeometryType} */ (value),
geometryFunction: geometryFunction,
maxPoints: maxPoints
});
map.addInteraction(draw);
}
}
/**
* Let user change the geometry type.
* #param {Event} e Change event.
*/
typeSelect.onchange = function(e) {
map.removeInteraction(draw);
addInteraction();
};
addInteraction();
} //end init
</script>
</head>
<body onload="init()">
<div id="map" style="width: 800px; height: 600px"></div>
<form class="form-inline">
<label>Geometry type </label>
<select id="type">
<option value="None">None</option>
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
</select>
</form>
</body>
</html>
Register a listener on ol.source.Vector and wait until the drawn feature is added:
source.on('addfeature', function(evt){
var feature = evt.feature;
var coords = feature.getGeometry().getCoordinates();
});
Use drawend event
drawend (ol.interaction.DrawEvent) - Triggered upon feature draw ends
Ex:
this.draw = new ol.interaction.Draw();
this.draw.on('drawend', function(evt){
//in evt you will get ol.feature
// from ol.feature get the geometry and than get coordinates
});
Let me know if I am wrong.

Range Rings in Google Maps V3

I have a script that was written a long time ago and not by me that I have updated from V2 to V3 and I am trying to draw range rings from a centered LatLng point. This worked in V2 but it is not working in V3 and I can't figure out why as I know some of the code is depreciated but not sure what it needs to be replaced with.
//Function to draw circles
function doDrawCircle(circleUnits, center, circleRadius, liColor, liWidth, liOpa, fillColor, fillOpa, opts, radials){
var bounds = new google.maps.LatLngBounds();
var circlePoints = Array();
with (Math) {
if (circleUnits == 'KM') {
var d = circleRadius/6378.8; // radians
}
else { //miles
var d = circleRadius/3963.189; // radians
}
var lat1 = (PI/180)* center.lat(); // radians
var lng1 = (PI/180)* center.lng(); // radians
for (var a = 0 ; a < 361 ; a++ ) {
var tc = (PI/180)*a;
var y = asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc));
var dlng = atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(y));
var x = ((lng1-dlng+PI) % (2*PI)) - PI ; // MOD function
var point = new google.maps.LatLng(parseFloat(y*(180/PI)),parseFloat(x*(180/PI)));
circlePoints.push(point);
bounds.extend(point);
if(a==0){
var offset = new google.maps.Size(-5,0); // Added the offset - mile markers look a bit better
var label = new ELabel(point, circleRadius, "style1", offset, 40);
map.addOverlay(label);
}
if (((a==0) || (a==45) || (a==90) || (a==135) || (a==180) || (a==225) || (a==270) || (a==315)) && radials) {
//if (((a==0) || (a==45) || (a==90) || (a==135) || (a==180)) && radials) {
var pline = new google.maps.Polyline([center,point] , liColor, liWidth, liOpa);
map.addOverlay(pline);
}
}
var poly = new google.maps.Polygon(circlePoints, liColor, liWidth, liOpa, fillColor, fillOpa, opts);
map.addOverlay(poly); // Add a target circle to the map
map.setZoom(map.getBoundsZoomLevel(bounds)); // This sets the map bounds to be as big as the target circles, comment out if you don't want it
}
}
Then I have this within the initialize() function for the map.
// You can add circles, or change other parameters
// radials should be set to true for the maximum distance if you want radials
// doDrawCircle(circleUnits, center, circleRadius, lineColor, lineWidth, lineOpacity, fillColor, fillOpacity, opts, radials)
doDrawCircle('MI',llCenter, 62, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 124, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 187, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 249, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 312, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
doDrawCircle('MI',llCenter, 374, lcolor, 1, .7, "#FFFF00", 0, { clickable: false }, false);
// doDrawCircle('MI',llCenter, 374, lcolor, 1, .7, '#00FF00', 0, { clickable: false }, true); // This would add the radials
This is what it is suppose to look like. This is from the working V2 map.
V2 EXAMPLE
Link to full code
FULL MAP CODE
First thing you'll need to do is get the newest version of elabel.js for google maps V3 here:
https://github.com/erunyon/ELabel/blob/master/elabel.js
Then, the good news is you don't need all of that complicated math and stuff which you have going on in your doDrawCircle function. You can now make use of google.maps.Circle as well as the geometry library which must be included via the google maps script tag's url parameters using a 'libraries=geometry' parameter so we can get the text label placement position starting point via google.maps.geometry.spherical.computeOffset. And then I've included a little tweeking of the text placement below to look a bit more tidy.
Test case:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Circles</title>
<style type="text/css">
.style1 {
/* used for range numbers on rings */
color: #FFF;
font-size: 10px;
text-shadow: 2px 2px 2px #000;
font-weight: bold;
font-family: verdana, helvetica, arial, sans-serif;
background-color:black;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=geometry"></script>
<!-- elabel.js for google maps V3 from here: https://github.com/erunyon/ELabel/blob/master/elabel.js -->
<script src="elabel.js"></script>
<script>
function initialize() {
var i, meters, options, labelLocation, textLength, textXcenter, label,
//note I declared the actual font pixel size in .style1 css rule
//just to help with visualizing the way I'm positioning the label texts
textPixelSize = 10,
//will need to invert textYcenter as well as textXcenter to negative numbers later
textYcenter = (textPixelSize / 2) + 2, //2px tweak for 'y' position, approximation
mapOptions = {
zoom: 6,
center: new google.maps.LatLng(32.8297,-96.6486),
mapTypeId: google.maps.MapTypeId.HYBRID
},
ranges = [62, 124, 187, 249, 312, 374], //circle radii in miles
circles = [],
labels = [],
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
for (i = 0; i < ranges.length; i++) {
//convert miles to meters:
meters = ranges[i] / 0.00062137;
options = {
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 1,
fillOpacity: 0,
map: map,
center: mapOptions.center,
radius: meters
};
circles.push(new google.maps.Circle(options));//ta-da! easy circles in V3
//labelLocation will be a google.maps.LatLng object
labelLocation = google.maps.geometry.spherical.computeOffset(mapOptions.center, meters, 0);
textLength = (''+ranges[i]).length;
textXcenter = (textLength * textPixelSize) / 2; //approximation
label = new ELabel({
latlng: labelLocation,
label: ranges[i],
classname: 'style1',
offset: new google.maps.Size(-textXcenter, -textYcenter),//negative will move left and up
opacity: 100,
overlap: true,
clicktarget: false
});
label.setMap(map);
labels.push(label);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map_canvas" style="width:780px; height:600px; margin:10px auto;"></div>
</body>
</html>
EDIT:
Here is revised version which allows to toggle visibility of the rings via the 'Range' button. Also removed all the text label positioning adjustment math and replaced with using style classes for different length texts instead (makes it easier to just use em units in the styles if desired). Added LabelCircle constructor for easier encapsulation and simultaneous control of circles & labels.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Circles</title>
<style type="text/css">
.style1 {
/*used for range numbers on rings*/
color: #FFF;
font-size: .6em;
text-shadow: 2px 2px 2px #000;
font-weight: bold;
font-family: verdana, helvetica, arial, sans-serif;
background-color:black;
margin-top: -0.5em;
}
.d2 { /*two-digit numbers on rings*/
margin-left: -1em;
}
.d3 { /*three-digit numbers on rings*/
margin-left: -1.5em;
}
/*direct copy of your existing .button style rule*/
.button{
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
text-align: center;
position: relative;
font-family: Arial, sans-serif;
font-size: 13px;
font-weight:bold;
box-shadow: rgba(0, 0, 0, 0.4) 0 2px 4px;
-moz-box-shadow: rgba(0, 0, 0, 0.4) 0 2px 4px;
-webkit-box-shadow: rgba(0, 0, 0, 0.4) 0 2px 4px;
color: #000;
border: 1px solid #717B87;
background-color: #fff;
margin: 5px;
padding: 1px 6px;
overflow: hidden;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=geometry"></script>
<!-- elabel.js for google maps V3 from here: https://github.com/erunyon/ELabel/blob/master/elabel.js -->
<script src="elabel.js"></script>
<script>
function LabelCircle(options) {
this.circle = new google.maps.Circle(options.circleOptions);
this.label = new ELabel(options.labelOptions);
this.label.setMap(options.circleOptions.map);
this.isVisible = true;
}
LabelCircle.prototype.setVisible = function (bool) {
var method = (bool) ? 'show' : 'hide';
this.circle.setVisible(bool);
this.label[method]();
this.isVisible = bool;
};
//a direct copy of your existing function
function buttonControl(options) {
var control = document.createElement('DIV');
control.innerHTML = options.name;
control.className = 'button';
control.index = 1;
// Add the control to the map
options.gmap.controls[options.position].push(control);
google.maps.event.addDomListener(control, 'click', options.action);
return control;
}
function initialize() {
var i, meters, options, labelLocation, textLength, label,
mapOptions = {
zoom: 6,
center: new google.maps.LatLng(32.8297,-96.6486),
mapTypeId: google.maps.MapTypeId.HYBRID
},
ranges = [62, 124, 187, 249, 312, 374], //circle radii in miles
labelCircles = [],
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
for (i = 0; i < ranges.length; i++) {
//convert miles to meters:
meters = ranges[i] / 0.00062137;
//labelLocation will be a google.maps.LatLng object
labelLocation = google.maps.geometry.spherical.computeOffset(mapOptions.center, meters, 0);
//we'll use textLength below to add a class to the label
textLength = (''+ranges[i]).length;
options = {
circleOptions: {
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 1,
fillColor: 'transparent',
fillOpacity: 0,
map: map,
center: mapOptions.center,
radius: meters
},
labelOptions: {
latlng: labelLocation,
label: ranges[i],
classname: 'style1 d' + textLength,
//offset: //no longer needed, using style classes
opacity: 100,
overlap: true,
clicktarget: false
}
};
labelCircles.push(new LabelCircle(options));
}
var rangeOptions = {
gmap: map,
name: 'Range',
position: google.maps.ControlPosition.TOP_RIGHT,
action: function(){
for (var tmp, i = 0; i < labelCircles.length; i++) {
tmp = labelCircles[i];
tmp.setVisible(!tmp.isVisible);
}
}
};
var rangeButton = buttonControl(rangeOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map_canvas" style="width:780px; height:600px; margin:10px auto;"></div>
</body>
</html>

Categories