I have a google map where I load geometry data to the data layer using geoJSON. I bind to the following event in the data layer.
map.data.addListener('click', function (event) { console.log(event);});
How can I trigger this event manually? I know I can trigger the click event on a marker manually, but it is triggered through google.maps.event.
That should be done with google.maps.event.trigger.
Try this (not sure):
// invoke a click
google.maps.event.trigger(map.data, 'click');
While Emmanuel's answer is technically correct, I would like to expand on it because I struggled for 2-3 hours to get this working.
In my code, I have a predefined click event function which was using feature object.
Here is my click event where I have used feature object:
transLayerData.addListener('click', function (event) {
var lfeature = event.feature;
var html = lfeature.getProperty('popupInfo');
infowindow.setContent(html);
infowindow.setPosition(event.latLng);
infowindow.setOptions({pixelOffset: new google.maps.Size(0,-34)});
infowindow.open(myMap);
});
If you are using a feature object in your predefined data layer click function (like above) , it is important that you pass the feature object and you create an event object with feature object in it.
Here is my code which gets the lat and long out of feature object and creates an event object:
var featureGeometry = feature.getGeometry();
var lsType = featureGeometry.getType();
var isLineData = false;
var lsType = featureGeometry.getType();
if ((lsType == 'LineString') || (lsType == 'MultiLineString') || (lsType == 'LinearRing') || (lsType == 'Polygon') | (lsType == 'MultiPolygon')) {
isLineData = true;
}
var featurePosition;
if (isLineData) {
// will center the map on the first vertex of the first LineString
var tmp = featureGeometry.getAt(0);
featurePosition = featureGeometry.getAt(0);
// following will set line's storke weight to 10
feature.setProperty('strokeWeight', 10);
} else{
featurePosition = featureGeometry.get();
}
myMap.setZoom(10);
myMap.setCenter(featurePosition);
var llat = featurePosition.lat();
var llong = featurePosition.lng();
// Creating event with the feature object is important. Especially if you have your very own feature click method defined
var lEvent = {
stop: null,
latLng: new google.maps.LatLng(llat, llong),
feature: feature,
}
// transLayerData is your data layer object.
// This is how I have defined my translayer object:
// transLayerData = new google.maps.Data({ map: myMap });
if (!isLineData) {
google.maps.event.trigger(transLayerData, 'click', lEvent);
} else {
google.maps.event.trigger(transLayerData, 'mouseover', lEvent);
}
}
Related
To react to specific space handlers I typically do this -
var fooHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
fooHandler.setInputAction(function(movement){
// do stuff
}, Cesium.ScreenSpaceEventType.WHEEL);
This function would be limited to WHEEL inputs. I have a couple of things that I need to do every time the camera changes position or height. I tried creating an event handler for the camera in a fashion similar to the above, and then calling camera.positionCartographic within that function, but to no avail.
Is there an event in Cesium that captures any movement?
You don't want to use ScreenSpaceEventHandler to do this. Instead, you subscribe to the preRender event and compare the camera position from last frame. Here's some sample code for you:
var lastTime = Cesium.getTimestamp();
var lastPosition = viewer.scene.camera.position.clone();
function preRender(scene) {
var time = Cesium.getTimestamp();
var position = scene.camera.position;
if (!Cesium.Cartesian3.equalsEpsilon(lastPosition, position, Cesium.Math.EPSILON4)) {
document.getElementById('viewChanged').style.display = 'block';
lastTime = time;
} else if (time - lastTime > 250) {
//hide the 'view changed' message after 250 ms of inactivity
lastTime = time;
document.getElementById('viewChanged').style.display = 'none';
}
lastPosition = position.clone();
}
viewer.scene.preRender.addEventListener(preRender);
We plan on adding a viewChanged event to Cesium some time soon, perhaps with 1.8, but this code will continue to work after that and you'll be able to switch to the event at your leisure.
If you want a live demo of the above code, see this port of the view changed Google Earth demo we did in Cesium: http://analyticalgraphicsinc.github.io/cesium-google-earth-examples/examples/viewchangeEvent.html
Here's what I ended up doing:
_preRender = function (scene) {
var currentPosition = scene.camera.position;
if (!Cesium.Cartesian3.equalsEpsilon(_lastPosition, currentPosition, Cesium.Math.EPSILON4)) {
_lastPosition = currentPosition.clone();
if (typeof _positionChangeTimeout !== 'undefined' && _positionChangeTimeout !== null)
{
clearTimeout(_positionChangeTimeout);
}
var currentPositionCartographic = scene.camera.positionCartographic;
_positionChangeTimeout = setTimeout(function() {
if (typeof _positionChangeListener === 'function' && _positionChangeListener !== null)
{
_positionChangeListener({
lat: Cesium.Math.toDegrees(currentPositionCartographic.latitude),
long: Cesium.Math.toDegrees(currentPositionCartographic.longitude),
zoomLevel: _calcZoomForAltitude(currentPositionCartographic.height, currentPositionCartographic.latitude)
});
}
}, 250);
}
}
I would like to use leaflet.draw to create outlines of regions. I have managed to get this working ok: https://www.mapbox.com/mapbox.js/example/v1.0.0/leaflet-draw/
Now I'd like to save the data for each polygon to a mysql table. Am a little stuck on how I would go about exporting the data and the format I should be doing it in.
If possible I'd like to pull the data back into a mapbox/leaflet map in the future so guess something like geojson would be good.
So you could use draw:created to capture the layer, convert it to geojson then stringify it to save in your database. I've only done this once and it was dirty but worked.
map.on('draw:created', function (e) {
var type = e.layerType;
var layer = e.layer;
var shape = layer.toGeoJSON()
var shape_for_db = JSON.stringify(shape);
});
If you want to collect the coordinates, you can do it this way:
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
drawnItems.addLayer(layer);
var shapes = getShapes(drawnItems);
// Process them any way you want and save to DB
...
});
var getShapes = function(drawnItems) {
var shapes = [];
drawnItems.eachLayer(function(layer) {
// Note: Rectangle extends Polygon. Polygon extends Polyline.
// Therefore, all of them are instances of Polyline
if (layer instanceof L.Polyline) {
shapes.push(layer.getLatLngs())
}
if (layer instanceof L.Circle) {
shapes.push([layer.getLatLng()])
}
if (layer instanceof L.Marker) {
shapes.push([layer.getLatLng()]);
}
});
return shapes;
};
map.on('draw:created', function (e) {
var type = e.layerType;
var layer = e.layer;
var shape = layer.toGeoJSON()
var shape_for_db = JSON.stringify(shape);
});
// restore
L.geoJSON(JSON.parse(shape_for_db)).addTo(mymap);
#Michael Evans method should work if you want to use GeoJSON.
If you want to save LatLngs points for each shape you could do something like this:
map.on('draw:created', function (e) {
var type = e.layerType;
var layer = e.layer;
var latLngs;
if (type === 'circle') {
latLngs = layer.getLatLng();
}
else
latLngs = layer.getLatLngs(); // Returns an array of the points in the path.
// process latLngs as you see fit and then save
}
Don't forget the radius of the circle
if (layer instanceof L.Circle) {
shapes.push([layer.getLatLng()],layer.getRadius())
}
PS that statement may not get the proper formatting but you see the point. (Or rather the radius as well as the point ;-)
Get shares as associative array + circle radius
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('Call Point!');
}
drawnItems.addLayer(layer);
var shapes = getShapes(drawnItems);
console.log("shapes",shapes);
});
var getShapes = function (drawnItems) {
var shapes = [];
shapes["polyline"] = [];
shapes["circle"] = [];
shapes["marker"] = [];
drawnItems.eachLayer(function (layer) {
// Note: Rectangle extends Polygon. Polygon extends Polyline.
// Therefore, all of them are instances of Polyline
if (layer instanceof L.Polyline) {
shapes["polyline"].push(layer.getLatLngs())
}
if (layer instanceof L.Circle) {
shapes["circle"].push([layer.getLatLng()])
}
if (layer instanceof L.Marker) {
shapes["marker"].push([layer.getLatLng()],layer.getRadius());
}
});
return shapes;
};
For me it worked this:
map.on(L.Draw.Event.CREATED, function (e) {
map.addLayer(e.layer);
var points = e.layer.getLatLngs();
puncte1=points.join(',');
puncte1=puncte1.toString();
//puncte1 = puncte1.replace(/[{}]/g, '');
puncte1=points.join(',').match(/([\d\.]+)/g).join(',')
//this is the field where u want to add the coordinates
$('#geo').val(puncte1);
});
For me it worked this:
after get coordinates send to php file with ajax then save to db
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Set the title to show on the polygon button
L.drawLocal.draw.toolbar.buttons.polygon = 'Draw a polygon!';
var drawControl = new L.Control.Draw({
position: 'topright',
draw: {
polyline: true,
polygon: true,
circle: true,
marker: true
},
edit: {
featureGroup: drawnItems,
remove: true
}
});
map.addControl(drawControl);
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('');
}
drawnItems.addLayer(layer);
shape_for_db = layer.getLatLngs();
SEND TO PHP FILE enter code hereWITH AJAX
var form_data = new FormData();
form_data.append("shape_for_db",shape_for_db);
form_data.append("name", $('#nameCordinate').val());
$.ajax({
url: 'assets/map_create.php', // point to server-side PHP script
dataType: 'text', // what to expect back from the PHP script, if anything
cache: false,
contentType: false,
processData: false,
data: form_data,
type: 'post',
success: function (php_script_response) {
var tmp = php_script_response.split(',');
alert(tmp );
}
});
});
map.on(L.Draw.Event.EDITED, function (e) {
var layers = e.layers;
var countOfEditedLayers = 0;
layers.eachLayer(function (layer) {
countOfEditedLayers++;
});
console.log("Edited " + countOfEditedLayers + " layers");
});
L.DomUtil.get('changeColor').onclick = function () {
drawControl.setDrawingOptions({rectangle: {shapeOptions: {color: '#004a80'}}});
};
I have a marker on the map to which I want to bind two events:
click
dblclick
I want to do the following:
When user clicks on the marker, map should zoom-in and will show
more detailed map.
I want to bind 'dblclick' event to the same marker so that it will
load some third-party reports in adjacent 'div' element.
In other words, I want it to behave differently when user clicks or dblclicks. But the problem is, when I bind both these event to marker and user 'double clicks' the marker, 'click' handler is getting fired, which I don't want to let it happen.
Is it true that, when user double-clicks, click event is also fired? If so, how to prevent it from triggering 'click' event when user actually double-clicked?
Is there any way so that I can do different things on either click and double-click event of the marker?
It's a known nuance of the api, you need to install a click counter timeout, like this:
function createMap2() {
var infoWindow = new google.maps.InfoWindow();
var map = new google.maps.Map(document.getElementById("map2"), myOptions);
var doubleClicked=false;
var clickEvent;
google.maps.event.addListener(map, 'dblclick', function(event) {
doubleClicked=true;
});
function handleClick() {
if (!doubleClicked) {
infoWindow.setPosition(clickEvent.latLng);
infoWindow.setContent(createInfo(clickEvent));
infoWindow.open(map);
}
}
google.maps.event.addListener(map, 'click', function(event) {
clickEvent = event;
doubleClicked = false;
window.setTimeout(handleClick, 250);
});
}
Above code extracted from http://www.william-map.com/20100506/1/v3click.htm
Check out these links for more info:
https://groups.google.com/forum/?fromgroups=#!topic/google-maps-js-api-v3/YRAvYHngeNk
https://groups.google.com/forum/?fromgroups=#!topic/google-maps-js-api-v3/2MomDiLMEiw
You can use a pre-handler function that separates single from double clicks. In this case, the second click must come within 500 miliseconds of the first one:
//Global vars
var G = google.maps;
var clickTimeOut = null;
G.event.addListener(marker,'click',mClick);
function mClick(mev) {
if (clickTimeOut) {
window.clearTimeout(clickTimeOut);
clickTimeOut = null;
doubleClick(mev);
}
else {
clickTimeOut = window.setTimeout(function(){singleClick(mev)},500);
}
}
function doubleClick(mev) {
// handle double click here
}
function singleClick(mev) {
window.clearTimeout(clckTimeOut);
clickTimeOut = null;
// handle single click here
}
mev is the mouseEvent object that the event handlers receive as parameter.
I cannot seem to figure out why the object returned by getProjection() is undefined. Here is my code:
// Handles the completion of the rectangle
var ne = recBounds.getNorthEast();
var sw = recBounds.getSouthWest();
$("#map_tools_selat").attr( 'value', sw.lat() );
$("#map_tools_nwlat").attr( 'value', ne.lat() );
$("#map_tools_selng").attr( 'value', ne.lng() );
$("#map_tools_nwlng").attr( 'value', sw.lng() );
// Set Zoom Level
$("#map_tools_zoomlevel").attr( 'value', HAR.map.getZoom()+1 );
document.getElementById("map_tools_centerLat").value = HAR.map.getCenter().lat();
document.getElementById("map_tools_centerLong").value = HAR.map.getCenter().lng();
// All this junk below is for getting pixel coordinates for a lat/lng =/
MyOverlay.prototype = new google.maps.OverlayView();
MyOverlay.prototype.onAdd = function() { }
MyOverlay.prototype.onRemove = function() { }
MyOverlay.prototype.draw = function() { }
function MyOverlay(map) { this.setMap(map); }
var overlay = new MyOverlay(HAR.map);
var projection = overlay.getProjection();
// END - all the junk
var p = projection.fromLatLngToContainerPixel(recBounds.getCenter());
alert(p.x+", "+p.y);
My error is: Cannot call method 'fromLatLngToContainerPixel' of undefined
Actually, i the reason why this happens is because the projection object is created after the map is idle after panning / zooming. So, a better solution is to listen on the idle event of the google.maps.Map object, and get a reference to the projection there:
// Create your map and overlay
var map;
MyOverlay.prototype = new google.maps.OverlayView();
MyOverlay.prototype.onAdd = function() { }
MyOverlay.prototype.onRemove = function() { }
MyOverlay.prototype.draw = function() { }
function MyOverlay(map) { this.setMap(map); }
var overlay = new MyOverlay(map);
var projection;
// Wait for idle map
google.maps.event.addListener(map, 'idle', function() {
// Get projection
projection = overlay.getProjection();
})
I kind of figured out what was going on. Even though it is still not crystal clear why this happens, I know that I had to instantiate the variable "overlay" right after instantiating my google map (HAR.map). So I practically moved that code snippet into my HAR class and now i use:
HAR.canvassOverlay.getProjection().fromLatLngToContainerPixel( recBounds.getCenter() );
So now, every time I create a map via my class "HAR" I also have a parallel OverlayView object within my class.
The Error could have been with losing scope of my class object, but I think it was more of the map event "projection_changed" not being fired. I got a hint from the map API docs for map class, under method getProjection():
"Returns the current Projection. If the map is not yet initialized (i.e. the mapType is still null) then the result is null. Listen to projection_changed and check its value to ensure it is not null."
If you are getting the similar issue, make sure that you assign your overlayView.setMAP( YOUR_MAP_OBJECT ) closely after instantiating the map object.
So this gets auto generated through the controller and I think I'm just overlooking something but the output is just like this
google.load("maps", "2.x", {"language" : "en"});
function initialize() {
if (GBrowserIsCompatible()) {
// Initialize the GMap
var map = new google.maps.Map2(document.getElementById("map"));
map.addControl(new google.maps.SmallMapControl());
map.setCenter(new google.maps.LatLng(30.226632, -97.935056), 10, G_NORMAL_MAP);
// Build custom marker icons
var tinyIcon = new google.maps.Icon();
tinyIcon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
tinyIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
tinyIcon.iconSize = new google.maps.Size(12,20);
tinyIcon.shadowSize = new google.maps.Size(22,20);
tinyIcon.iconAnchor = new google.maps.Point(6,20);
tinyIcon.infoWindowAnchor = new google.maps.Point(5,1);
// Show map points
var m1 = new google.maps.Marker(new google.maps.LatLng(35.2602340, -93.7939480), {icon:tinyIcon,bouncy:1});
google.maps.Event.addListener(m1, "click", function()
{
m1.openInfoWindowHtml(
'1<br />test,TX'
);
});
map.addOverlay(m1);
var m2 = new google.maps.Marker(new google.maps.LatLng(35.2810510, -93.8246510), {icon:tinyIcon,bouncy:1});
google.maps.Event.addListener(m2, "click", function()
{
m2.openInfoWindowHtml(
'test<br />test,Texas'
);
});
map.addOverlay(m2);
}
google.setOnLoadCallback(initialize);
So when i go to use a trigger event
google.maps.event.trigger(markers[m3], 'click');
Nothing happens, and I cant figure out the correct trigger to make it do so...
Based on the code sample you posted there is no markers[m3] defined, wouldn't you need to use google.maps.event.trigger(m2, 'click'); ? (m3 isn't defined at all in that code sample)