Mouse move event for polyline vertex in google maps api v3 - google-maps-api-3

I would like to show an info window when I'm moving a vertex on an editable polyline.
This info will show the distance and heading to the prior vertex on the polyline. When I drop the vertex, the info window must be closed.
The problem is polyline hasn't a drag event over vertex. I'll try with polyline's mousemove but It is fired after move has finished.
In the next code, I show an example what I said. I have a polyline (flightPath). If I click on the last vertex I will like to move a marker at the same time. But It doesn't work. The marker is moved after movement is finished.
google.maps.event.addListener(flightPath, 'mousemove', function (event) {
if (typeof event.vertex === "undefined") {
moveline = 0
}
else {
if (event.vertex == (flightPath.getPath().getLength()-1)) {
var path = flightPath.getPath();
marker.setPosition(path.getAt(event.vertex));
}
}
});
Some suggestion?
Note: My polyline is editable.
Thanks

You could manage a drag end event on the marker and change de latLng of the vertex:
google.maps.event.addListener(marker, 'dragend', function(evt){
var vertex = marker.get('vertex');
var path = flightPath.getPath();
var newPath = Array.prototype.slice.call(path).filter(
function(element, index){
return index < vertex;
}).concat([evt.latLng],
Array.prototype.slice.call(path).filter(
function(element, index){
return index > vertex;
}));
flightPath.setPath(newPath);
});
I'm sorry for my bad english but i hope it helps.

Related

Here Maps API: Detecting when a Marker is dragged and dropped onto a Polyline

I have draggable markers on a Here Map, and I'd like to detect when a marker is dragged and dropped onto a Polyline. I haven't been able to find a good way to detect that the marker is dropped on or near the polyline. It would be nice if I could add an "dragend" event listener to the Polyline object, but that doesn't seem to be supported on objects other than the actual map.
Another approach would be to determine the distance to the Polyline from the point that the dragend occurs, but I haven't found a straightforward way to calculate that distance. (Though I've found the example for finding the nearest marker to a point.)
Any suggestions?
It is possible to add dragend event listener on map objects.
This code should work for you (in 3.0 API version):
var lineString = new H.geo.LineString([0, 0, 0, 50, 50, 0]),
polyline = new H.map.Polyline(lineString, {style: {lineWidth: 15, strokeColor: 'red'}}),
marker = new H.map.Marker({lat: 30, lng: 0});
// Ensure that the marker can receive drag events
marker.draggable = true;
// add objects to the map
map.addObjects([polyline, marker]);
// set map center and zoom
map.setCenter({lat: 30, lng: 0});
map.setZoom(3);
// disable map's behavior and calculate the offset between mouse and target's position
// when starting to drag a marker object:
marker.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer,
targetPosition = map.geoToScreen(target.getGeometry());
target['offset'] = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}, false);
// Listen to the drag event and move the position of the marker
marker.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
target.setGeometry(map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));
}, false);
// re-enable behavior and check if marker was dropped on polyline
marker.addEventListener('dragend', function(ev) {
behavior.enable();
var pointer = ev.currentPointer,
objects = map.getObjectsAt(pointer.viewportX, pointer.viewportY),
droppedOnPolyline = false;
objects.forEach(function(object) {
if (object === polyline) {
droppedOnPolyline = true;
}
});
console.log('marker dropped on polyline? %s', droppedOnPolyline);
}, false);

Aframe cardboard movement

I want to be able to move in my VR world by looking around and holding down the cardboard button to move. I have tried for 2 hours and couldn't figure it out. I really don't want to use teleportation as my solution.
I'd throw this in an aframe component, and use the three.js API:
In the init check whether the mouse is up or down.
In the tick find out the rotation as a world matrix using extractRotation(mesh.matrix), apply it to a forward vector using direction.applyMatrix4(matrix), and add it to the current camera position.
AFRAME.registerComponent("foo", {
init: function() {
this.mouseDown = false
this.el.addEventListener("mousedown", (e) => {
this.mouseDown = true
})
this.el.addEventListener("mouseup", (e) => {
this.mouseDown = false
})
},
tick: function() {
if (this.mouseDown) {
let pos = this.el.getAttribute("position")
let mesh = this.el.object3D
var matrix = new THREE.Matrix4();
var direction = new THREE.Vector3(0, 0, -0.1);
matrix.extractRotation(mesh.matrix);
direction.applyMatrix4(matrix)
direction.add(new THREE.Vector3(pos.x, pos.y, pos.z))
this.el.setAttribute("position", direction)
}
}
})
Working fiddle here.

How to get LatLngBounds of feature polygon geometry in google maps v3?

I have a lot of polygonal features loaded with loadGeoJson and I'd like to get the latLngBounds of each. Do I need to write a function that iterates through every lat long pair in the polygon and does an extend() on a LatLngBounds for each, or is there a better way? (If not, I can probably figure out how to iterate through the polygon vertices but pointers to an example of that would be welcome)
The Polygon-features doesn't have a property that exposes the bounds, you have to calculate it on your own.
Example:
//loadGeoJson runs asnchronously, listen to the addfeature-event
google.maps.event.addListener(map.data,'addfeature',function(e){
//check for a polygon
if(e.feature.getGeometry().getType()==='Polygon'){
//initialize the bounds
var bounds=new google.maps.LatLngBounds();
//iterate over the paths
e.feature.getGeometry().getArray().forEach(function(path){
//iterate over the points in the path
path.getArray().forEach(function(latLng){
//extend the bounds
bounds.extend(latLng);
});
});
//now use the bounds
e.feature.setProperty('bounds',bounds);
}
});
Demo: http://jsfiddle.net/doktormolle/qtDR6/
In Google Maps JavaScript API v2, Polygon had a getBounds() method, but that doesn’t exist for v3 Polygon. Here’s the solution:
if (!google.maps.Polygon.prototype.getBounds) {
google.maps.Polygon.prototype.getBounds = function () {
var bounds = new google.maps.LatLngBounds();
this.getPath().forEach(function (element, index) { bounds.extend(element); });
return bounds;
}
}
Here's another solution for v3 Polygon :
var bounds = new google.maps.LatLngBounds();
map.data.forEach(function(feature){
if(feature.getGeometry().getType() === 'Polygon'){
feature.getGeometry().forEachLatLng(function(latlng){
bounds.extend(latlng);
});
}
});

Extend polyline and handle mouse event

I write JS app where I draw a lot of polylines using array of points, but in avery point I have some additional properties in this point (GPS data, speed etc).
I want to show these additional props onmouseover or onmouseclick event.
I have two ways:
use the standard polylines and event handler. But in this case I can't to determine additional properties for start point of this polyline cause I can't to save these props in polyline properties. There is one solution - save in array additional properties and try to find them by LatLng of first point of the polyline, but it's too slow I guess..
extend polyline and save additional properties in new Object, but I can't to extend mouse events :(
To extend polyline I use this code:
function myPolyline(prop, opts){
this.prop = prop;
this.Polyline = new google.maps.Polyline(opts);
}
myPolyline.prototype.setMap = function(map) {
return this.Polyline.setMap(map);
}
myPolyline.prototype.getPath = function() {
return this.Polyline.getPath();
}
myPolyline.prototype.addListener= function(prop) {
return this.Polyline.addListener();
}
myPolyline.prototype.getProp= function() {
return this.prop;
}
myPolyline.prototype.setProp= function(prop) {
return this.prop = prop;
}
and create new object in for loop (i - index of current point in array of points) like that:
var polyline_opts = {
path: line_points,
strokeColor: color,
geodesic: true,
strokeOpacity: 0.5,
strokeWeight: 4,
icons: [
{
icon: lineSymbol,
offset: '25px',
repeat: '50px'
}
],
map: map
};
var add_prop = {
id: i,
device_id: device_id
};
...
devices_properties[device_id].tracks[(i-1)] = new myPolyline(add_prop, polyline_opts);
Where:
line_points - array of points (just two points),
i - current point index
devices_properties[device_id].tracks - array of extended polylines (with add properties) by my device_id index
After that I set event handler like that:
var tmp = devices_properties[device_id].tracks[(i-1)];
google.maps.event.addListener(tmp.Polyline, 'click', function(e) {
...
console.log(tmp.prop.id);
...
}
But in this case I always get the same id in console..
When I use
google.maps.event.addListener(devices_properties[device_id].tracks[(i-1)].Polyline, 'click', function(e) {
...
console.log(???); // How to get parent of polyline fired the event?
...
}
I don't know how to get parent of polyline fired the event?
I answer my own question - It's done, I've just have some troubles with using "for" instead "$.each" :)
Before I use:
for ( i = 1; i < devices_properties[device_id].history_points.length; i++ ) {
...
create myPolyline
...
}
and it's doesn't work - created one event handle.
After:
$.each(devices_properties[device_id].history_points, function(i, tmp){
...
create myPolyline ()
...
}
and it works - create a lot of event handlers.
To handle event I use this:
google.maps.event.addListener(c_polyline.Polyline, 'mouseover', function(e) {
var prop = c_polyline.getProp();
...
console.log(prop.id, prop.device_id);
}

Moving a shape in kineticJS towards mouse click

I am experimenting with Meteor and KineticJS. What I'm trying to do is to create a shape, and move it towards a mouse click on the stage. The position should be saved to the mongoDB so that all connected clients can be updated.
I haven't gotten far yet, but this is what I've got. I basically need a way to do two things:
How can I make a shape move towards the mouse click on the stage
and stop when it gets there?
Is there a better way of checking
the current position of a shape, other than the gameLoop that I
tried below? It works, but it feels wrong.
Thank you!
//client.js code
var player = null;
var playerAnim = null;
Template.container.rendered = function () {
var myCanvas = document.getElementById('myCanvas');
var stage = new Kinetic.Stage({
container: myCanvas,
width: 1024,
height: 1024
});
var layer = new Kinetic.Layer();
// add the layer to the stage
stage.add(layer);
// add click listener for the stage
$(stage.getContent()).on('click', function(evt) {
//stage was clicked
//Find the player shape in the database
Players.find().forEach(function (dbShape) {
player = new Kinetic.RegularPolygon(dbShape);
// setup an animation to move the player to the right
playerAnim = new Kinetic.Animation(function(frame) {
var velocity = 50;
var dist = velocity * (frame.timeDiff / 1000);
player.move(dist, 0);
Players.update(dbShape._id, {$set: {x: player.attrs.x, y: player.attrs.y}});
}, layer);
playerAnim.start();
layer.add(player);
layer.draw();
});
});
//make a gameLoop to check the position and stop the animation
Meteor.setInterval(function(gameLoop){
if(player.attrs.x > 500){
playerAnim.stop();
}
}, 500);
Meteor.autosubscribe(function () {
// clear the canvas
if (layer) {
layer.removeChildren();
layer.clear();
}
// populate the canvas with the Shapes collection
Players.find().forEach(function (dbShape) {
var player = new Kinetic.RegularPolygon(dbShape);
layer.add(player);
layer.draw();
});
});
}
I would use a tween to do this. Grab your object, get mouse position, and on mousedown or click create a Tween for your node to that mouse position.
layer.on('mousedown', function() {
var mousePos = stage.getMousePosition();
var tween = new Kinetic.Tween({
node: rect,
duration: 1,
x: mousePos.x,
y: mousePos.y,
opacity: 1,
strokeWidth: 6,
scaleX: 1.5
}).play();
});
JSFiddle
Note: To make the layer clickable, we need to add a transparent rectangle with the size of the width and height of the stage to the layer. See in the jsfiddle the Kinetic.Rect I made named var bg
Would putting the check inside the animation work for you?
playerAnim = new Kinetic.Animation(function(frame) {
var velocity = 50;
var dist = velocity * (frame.timeDiff / 1000);
player.move(dist, 0);
Players.update(dbShape._id, {$set: {x: player.attrs.x, y: player.attrs.y}});
if(player.getX() > 500){
this.stop();
}
}, layer);

Resources