I am tryign to figure out MVCArray() in google maps v3. I'm using code written by GeoJason as an example. I attached a click event to the markers to get its LatLng postion. It works well but I need to update the MVCArray on the new postion if a marker is dragged to a new location. This part has me stumped.. Anyone know how to do this or can point me to a good resource which explains using MVCArray's? (besides coode docs, its not designed for newbies.. lol)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>GeoJason - Line Length and Polygon Area with Google Maps API v3 Demo</title>
<meta name="keywords" content="" />
<meta name="description" content="Demo of how to get Line Length and Polygon Area with Google Maps API v3" />
<link rel="stylesheet" type="text/css" href="style/default.css" />
<!-- Script -->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript" src="js/jquery/jquery-1.4.2.js"></script>
<script type="text/javascript">
var map;
var markerImageDefault = new google.maps.MarkerImage('images/markers/measure-vertex.png',null, null, new google.maps.Point(5,5));
var markerImageHover = new google.maps.MarkerImage('images/markers/measure-vertex-hover.png',null, null, new google.maps.Point(8,8));
var measure = {
ll:new google.maps.MVCArray(),
markers:[],
line:null,
poly:null
};
function Init(){
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 15,
center: new google.maps.LatLng(34.96762, -80.47372),
mapTypeId: google.maps.MapTypeId.ROADMAP,
/* Make the map cursor a crosshair so the user thinks they should click something */
draggableCursor:'crosshair'
});
google.maps.event.addListener(map,'click',function(evt){
measureAdd(evt.latLng);
});
}
function measureAdd(ll){
var marker = new google.maps.Marker({
map:map,
position:ll,
draggable:true,
/* Let the user know they can drag the markers to change shape */
title:'Drag me to change the polygon\'s shape',
icon: markerImageDefault
});
var count = measure.ll.push(ll);
var llIndex = count-1;
if (count>2) /* We've got atleast 3 points, we can measure area */
measureCalc();
/* when dragging stops, and there are more than 2 points in our MVCArray, recalculate length and area measurements */
google.maps.event.addListener(marker,'dragend',function(evt){
if (measure.ll.getLength()>2)
measureCalc();
});
/* when the user 'mouseover's a marker change the image so they know something is different (it's draggable) */
google.maps.event.addListener(marker,'mouseover',function(evt){
marker.setIcon(markerImageHover);
});
google.maps.event.addListener(marker,'mouseout',function(evt){
marker.setIcon(markerImageDefault);
});
// This will allow us to click on the first element to close the polygon
google.maps.event.addListener(marker,'click',function(evt){
//alert(ll + " : " + measure.markers[0].position);
console.log(ll.LatLng);
if(ll == measure.markers[0].position) // Only for the first item
{
alert("You clicked!");
}
});
/* when we drag a marker it resets its respective LatLng value in an MVCArray. Since we're changing a value in an MVCArray, any lines or polygons on the map that reference this MVCArray also change shape ... Perfect! */
google.maps.event.addListener(marker,'drag',function(evt){
measure.ll.setAt(llIndex,evt.latLng);
});
measure.markers.push(marker);
/* find out of the user placed a marker at the end of the polygon. */
if (measure.ll.getLength()>1){
/* We've got 2 points, we can draw a line now */
if (!measure.line){
measure.line = new google.maps.Polyline({
map:map,
clickable:false,
strokeColor:'#FF0000',
strokeOpacity:0.5,
strokeWeight:3,
path:measure.ll
});
}
if (measure.ll.getLength()>2){
/* We've got 3 points, we can draw a polygon now */
if (!measure.poly){
measure.poly = new google.maps.Polygon({
clickable:false,
map:map,
fillOpacity:0.25,
strokeOpacity:0,
paths:measure.ll
});
}
}
}
}
function measureReset(){
/* Remove Polygon */
if (measure.poly) {
measure.poly.setMap(null);
measure.poly = null;
}
/* Remove Line */
if (measure.line) {
measure.line.setMap(null);
measure.line = null;
}
/* remove all LatLngs from the MVCArray */
while (measure.ll.getLength()>0) measure.ll.pop();
/* remove all markers */
for (i=0;i<measure.markers.length;i++){
measure.markers[i].setMap(null);
}
$('#measure span').text('0');
}
function measureCalc(){
var points='';
measure.ll.forEach(function(latLng,ind){
/* build a string of points in (x,y|x,y|x,y|x,y) format */
points+=latLng.lng()+','+latLng.lat()+'|';
});
points=points.slice(0,points.length-1);
/* send a getJSON request to our webserver to get length and area measurements */
$.getJSON('http://api.geojason.info/v1/ws_geo_length_area.php?format=json&in_srid=4326&out_srid=2264&points='+points+'&callback=?',function(data){
if (parseInt(data.total_rows)>0){
/* calculate and inject values in their corresponding "span"s */
//var length = parseFloat(data.rows[0].row.length);
var area = parseFloat(data.rows[0].row.area);
//$('#measure-area-sqft').text(area.toFixed(0));
$('#measure-area-acres').text((area/43560).toFixed(3));
//$('#measure-length-feet').text(length.toFixed(0));
//$('#measure-length-meters').text((length*0.3048).toFixed(1));
}
});
}
</script>
</head>
<body onload="Init();">
<div id="header">Home - Back to Demos</div>
<h2>Line Length and Polygon Area with Google Maps API v3</h2>
<div id="map-canvas"></div>
<div id="content">
<p></p>
<div><input type="button" onclick="measureReset();" value="Clear Measure" /></div>
<div id="measure">
<div>Length: <span id="measure-length-feet">0</span> ft.</div>
<div>Length: <span id="measure-length-meters">0</span> met.</div>
<div>Area: <span id="measure-area-sqft">0</span> ft.²</div>
<div>Area: <span id="measure-area-acres">0</span> ac.</div>
</div>
</div>
</body>
</html>
I guess you need to bind each marker position to a vertex in your polyline (use bindTo method ) - a good example is here
http://gmaps-utility-gis.googlecode.com/svn/trunk/v3test/mvc/poly_bind.html
simple examples here
http://gmaps-samples-v3.googlecode.com/svn/trunk/rectangle-overlay/rectangle-overlay.html
http://gmaps-samples-v3.googlecode.com/svn/trunk/circle-overlay/circle-overlay.html
Related
I have created a simple html using the draggable marker example from here maps. I have adapted it to support IE 11 by adding reference to legacy js, meta tag and using P2D engine in map options. Also added two url parameters for coordinates. It works perfectly in IE11 and it loads and shows pan and zoom buttons in ms-access webbrowser but it keeps static, it's not draggable, but pan and zoom works.
The curious thing is that if I navigate to wego.here.com in the same webbrowser control then the map is draggable. So they're doing something else in the here maps main page that I'm not doing in my script.
I have also tried using Microsoft Web Browser from the activex controls list in access.
I need it to be draggable so I can pick the coordinates after the user changes the marker position.
This is my script:
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Draggable Marker</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-core-legacy.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service-legacy.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js" type="text/javascript" charset="utf-8"></script>
<style>
html, body { margin:0px; padding:0px; width: 100%; height: 100%; }
.main { height: 100%; }
</style>
</head>
<body id="markers-on-the-map">
<div class="main" style="width:100%" id="map"></div>
<input type="hidden" id="long" name="long">
<input type="hidden" id="lat" name="lat">
<script>
function addDraggableMarker(map, behavior){
var marker = new H.map.Marker({lat:latitud, lng:longitud}, {volatility: true});
// Ensure that the marker can receive drag events
marker.draggable = true;
map.addObject(marker);
// disable the default draggability of the underlying map
// and calculate the offset between mouse and target's position
// when starting to drag a marker object:
map.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
var targetPosition = map.geoToScreen(target.getGeometry());
target['offset'] = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}
}, false);
// re-enable the default draggability of the underlying map
// when dragging has completed
map.addEventListener('dragend', function(ev) {
var target = ev.target;
if (target instanceof H.map.Marker) {
$('#long').val(ev.target.b.lng);
$('#lat').val(ev.target.b.lat);
behavior.enable();
}
}, false);
// Listen to the drag event and move the position of the marker
// as necessary
map.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
target.setGeometry(map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));
}
}, false);
}
/**
* Boilerplate map initialization code starts below:
*/
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: '?????????????????????????????????'
});
var defaultLayers = platform.createDefaultLayers();
//url parameters
var query_string = {};
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = decodeURIComponent(pair[1]);
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]],decodeURIComponent(pair[1]) ];
query_string[pair[0]] = arr;
} else {
query_string[pair[0]].push(decodeURIComponent(pair[1]));
}
}
var latitud=query_string.lat;
var longitud=query_string.long;
//Step 2: initialize a map - this map is centered over Boston
var map = new H.Map(document.getElementById('map'),
defaultLayers.raster.normal.map, {
center: {lat:latitud, lng:longitud},
engineType: H.map.render.RenderEngine.EngineType.P2D,
zoom: 12,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
//window.addEventListener('resize', () => map.getViewPort().resize());
window.addEventListener('resize', function () {map.getViewPort().resize(); });
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
//var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Step 4: Create the default UI:
var ui = H.ui.UI.createDefault(map, defaultLayers, 'en-US');
// Add the click event listener.
addDraggableMarker(map, behavior);
</script>
</body>
</html>```
Check please on this static page
: your code works for my IE11
After having followed a mapbox tutorial, I managed to display a drone on a map.
My only question is :
How can I add a rotation parameter in my code (to display the drone-marker on different angles) ?
I have spent hours looking for examples but none corresponds to what I already wrote...
Thank you !
Here's the script :
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.43.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.43.0/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.marker {
background-image: url('MQ-1_Predator_silhouette.svg.png');
background-size: cover;
width: 61px;
height: 35px;
border-radius: 50%;
cursor: pointer;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoibWF0dGhpZXU2MyIsImEiOiJjamNob3I3cmgxam1kMzFzNzdja2ZvNmhuIn0.AyFos9o0afaaBU21CgrxXg';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
center: [-96, 37.8],
zoom: 3
});
// code from the next step will go here!
var geojson = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-90,40]
},
properties: {
title: 'Mapbox'
}
}]
};
// add markers to map
geojson.features.forEach(function(marker) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);
});
</script>
</body>
</html>
Mapbox offers inbuilt icon rotation feature under the heading of get bearing and icon rotation is handled internally once you find out geographical bearing between two pairs of LatLng and feed that value to get Bearing.
If you are using mapbox marker and are keen on rotating it, you can use css transform property (rotate()) and dynamically calculate the angle between two pairs of latLng and use that value in rotate property.
var dLon = destination[0]-origin[0];
var dLat = destination[1]-origin[1];
var angle = 180+(Math.atan2(dLon, dLat) * 180 / Math.PI);
var rotateString = "rotate(" + angle + "deg)";
var el = document.createElement('div');
el.className = 'marker';
var truckMarker = new mapboxgl.Marker(el)
el.style.transform = el.style.transform + rotateString;
In the last line it is important to append the rotate property because the transform property is already being updated as translate is called because of animation.
Works perfectly fine for me!!
If you're using Markers then you'll need to do the rotation yourself as part of the marker element style. This would probably only work if you disable map rotation, or unless you do something like https://github.com/mapbox/mapbox-gl-js/issues/3937#issuecomment-304916394 to account for the map rotation yourself.
If you're using Symbols then it's much easier as you can use https://www.mapbox.com/mapbox-gl-js/style-spec#layout-symbol-icon-rotate to set your rotation.
I want to use something like mouse hover or move on Google Maps. How can I draw a shape that I want but not a geometric one. I want it like ,when the mouse is clicked, it should draw(non-linear line) and when mouse is again clicked, drawing should end and a shape bounded closed area should be displayed. Is it possible? Maybe with coordinates?
I don't have an example for Google Maps, but here is one that I created for Bing Maps:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Event mouse down</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map, isDrawing, line;
function getMap()
{
map = new Microsoft.Maps.Map(document.getElementById('myMap'), {credentials: 'YOUR_BING_MAPS_KEY'});
Microsoft.Maps.Events.addHandler(map, 'mousedown', startDrawing);
Microsoft.Maps.Events.addHandler(map, 'mouseup', stopDrawing);
Microsoft.Maps.Events.addHandler(map, 'mousemove', mouseMoved);
}
function startDrawing(e)
{
try{
var point = new Microsoft.Maps.Point(e.getX(), e.getY());
var loc = e.target.tryPixelToLocation(point);
line = new Microsoft.Maps.Polyline([loc, loc]);
map.entities.push(line);
isDrawing = true;
map.setOptions({disablePanning: true, disableZooming: true});
}catch(x){}
}
function mouseMoved(e)
{
if(isDrawing){
try{
var point = new Microsoft.Maps.Point(e.getX(), e.getY());
var loc = e.target.tryPixelToLocation(point);
var locs = line.getLocations();
locs.push(loc);
line.setLocations(locs);
}catch(x){}
}
}
function stopDrawing()
{
isDrawing = false;
map.setOptions({disablePanning: false, disableZooming: false});
}
</script>
</head>
<body onload="getMap();">
<div id='myMap' style="position:relative; width:1000px; height:800px;"></div>
</body>
</html>
I'm trying to use canvas object on iPad; the user need to draw a free curve with the finger and when he releases the finger the system must close the curve and fill it.
Actually I wrote down the following code but the problem is that it draws but it does not close the path on finger release.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=768px, maximum-scale=1.0" />
<title>sketchpad</title>
<script type="text/javascript" charset="utf-8">
window.addEventListener('load',function(){
// get the canvas element and its context
var canvas = document.getElementById('sketchpad');
var context = canvas.getContext('2d');
var img = new Image();
img.src = 'imp_02.jpg';
context.drawImage(img,0,0,600,600);
var colorPurple = "#cb3594";
context.strokeStyle=colorPurple;
context.lineWidth = 5;
context.fillStyle = "red";
// create a drawer which tracks touch movements
var drawer = {
isDrawing: false,
touchstart: function(coors){
context.beginPath();
context.moveTo(coors.x, coors.y);
this.isDrawing = true;
},
touchmove: function(coors){
if (this.isDrawing) {
context.lineTo(coors.x, coors.y);
context.stroke();
}
},
touchend: function(coors){
if (this.isDrawing) {
context.touchmove(coors);
context.closePath();
this.isDrawing = false;
}
}
};
// create a function to pass touch events and coordinates to drawer
function draw(event){
// get the touch coordinates
var coors = {
x: event.targetTouches[0].pageX,
y: event.targetTouches[0].pageY
};
// pass the coordinates to the appropriate handler
drawer[event.type](coors);
}
// attach the touchstart, touchmove, touchend event listeners.
canvas.addEventListener('touchstart',draw, false);
canvas.addEventListener('touchmove',draw, false);
canvas.addEventListener('touchend',draw, false);
// prevent elastic scrolling
document.body.addEventListener('touchmove',function(event){
event.preventDefault();
},false); // end body.onTouchMove
},false); // end window.onLoad
</script>
<style type="text/css"><!--
body{margin:0;padding:0; font-family:Arial;}
#container{position:relative;}
#sketchpad{ border: 1px solid #000;}
--></style>
</head>
<body>
<div id="container">
<canvas id="sketchpad" width="766" height="944">
Sorry, your browser is not supported.
</canvas>
</div>
</body>
</html>
I don't understand what I missed.
Is there anyone who can help me..... I would appreciate a lot!!
You are fetching the touch end co-ordinates from a wrong array.
event object has one more array called changedTouches where you can find the co-ordinates of the point where the touch ended. These end co-ordinates are not in targetTouches array.
So you need
endCoordX = event.changedTouches[0].pageX;
endCoordY = event.changedTouches[0].pageY;
[modify the above code to fit into your scenario. hope you got the concept.... And seriuosly i too got stuck on the same point in the past and wasted more than an hour to know this fact....]
The API documentation gave me hopes last night with "bindInfoWindowHtml".
But it doesn't seem to replace the default infoWindow, even when you provide your own class etc.
I have tried using other ideas like the labeledmarker. But it doesn't support draggable markers. Hence can't use it in my application.
Here is the sample code which shows the info. window inside, the original bubble.
Isn't there a way to override that window as well !
`
<style type="text/css">
.infoWindowCustomClass
{
width: 500px;
height: 500px;
background-color: #CAEE96;
color: #666;
}
</style>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key="" type="text/javascript"></script>
<script type="text/javascript">
function load() {
if (GBrowserIsCompatible())
{
// Create our "tiny" marker icon
var blueIcon = new GIcon(G_DEFAULT_ICON);
blueIcon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png";
// Set up our GMarkerOptions object
markerOptions = { icon:blueIcon };
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(33.968064,-83.377047), 13);
markerOptions.title = "fart";
var point = new GLatLng(33.968064,-83.377047);
var marker = new GMarker(point);
var tempName = document.getElementById("infoWindowCustom");
marker.bindInfoWindowHtml(tempName);
map.addOverlay(marker);
}
}
</script>`
And here is the DIV -
<DIV id="infoWindowCustom" name="infoWindowCustom" class="infoWindowCustomClass">
Name : <TEXTAREA NAME="nameID" ID="nameID" ROWS="2" COLS="25"></TEXTAREA>
Comments : <TEXTAREA NAME="commentsID" ID="commentsID" ROWS="4" COLS="25"></TEXTAREA>
</DIV>
Solved it as below -
Instead of binding it as above, I take the lang/lats and launch a div at that place.
That seems to work just fine.