How to snap a polyline to a road with walking travelmode in Google Maps? - google-maps-api-2

II want an user to draw a route with polylines on GoogleMaps. I've found a way to snap a polyline ( example in the link, code in below ). The code works with the directions service to draw a polyline on a road, the only problem is this only works with G_TRAVELMODE_DRIVING but I want to use G_TRAVELMODE_WALKING and when you use WALKING you have to supply the map and a div in the constructor of the directions object. When I do that it automatically removes the last line and only displays the current line. I've tried several things like supplying the map as null, or leaving out the map in the constructor.. I've also tried to give a second map in the constructor, get the polylines from the directions service and display them on the right map. But nothing works! I'd appreciate it if someone could help me!
http://econym.org.uk/gmap/example_snappath.htm
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(53.7877, -2.9832),13)
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
var dirn = new GDirections();
var firstpoint = true;
var gmarkers = [];
var gpolys = [];
var dist = 0;
GEvent.addListener(map, "click", function(overlay,point) {
// == When the user clicks on a the map, get directiobns from that point to itself ==
if (!overlay) {
if (firstpoint) {
dirn.loadFromWaypoints([point.toUrlValue(6),point.toUrlValue(6)],{getPolyline:true});
} else {
dirn.loadFromWaypoints([gmarkers[gmarkers.length-1].getPoint(),point.toUrlValue(6)],{getPolyline:true});
}
}
});
// == when the load event completes, plot the point on the street ==
GEvent.addListener(dirn,"load", function() {
// snap to last vertex in the polyline
var n = dirn.getPolyline().getVertexCount();
var p=dirn.getPolyline().getVertex(n-1);
var marker=new GMarker(p);
map.addOverlay(marker);
// store the details
gmarkers.push(marker);
if (!firstpoint) {
map.addOverlay(dirn.getPolyline());
gpolys.push(dirn.getPolyline());
dist += dirn.getPolyline().Distance();
document.getElementById("distance").innerHTML="Path length: "+(dist/1000).toFixed(2)+" km. "+(dist/1609.344).toFixed(2)+" miles.";
}
firstpoint = false;
});
GEvent.addListener(dirn,"error", function() {
GLog.write("Failed: "+dirn.getStatus().code);
});
}
else {
alert("Sorry, the Google Maps API is not compatible with this browser");
}

I know it's an old post, but since no answer came forward and I've recently been working on this sort of code (and got it working), try swapping the addListener with this.
GEvent.addListener(map, "click", function(overlay,point) {
// == When the user clicks on a the map, get directiobns from that point to itself ==
if (!overlay) {
if (firstpoint) {
dirn1.loadFromWaypoints([point.toUrlValue(6),point.toUrlValue(6)],{ getPolyline:true,travelMode:G_TRAVEL_MODE_WALKING});
} else {
dirn1.loadFromWaypoints([gmarkers[gmarkers.length-1].getPoint(),point.toUrlValue(6)],{ getPolyline:true,travelMode:G_TRAVEL_MODE_WALKING});
}
}
});

Related

phaser.io how to draw over a path

I need to write a game like: https://robowhale.com/html5/drawing-letters/ with phaser.io library. I mean user must follow a path and draw for example letter "A".
basically, need to draw over a path, I checked almost all examples and tutorials, But couldn't find any proper tutorial or algorithm.
any help, link, source code or tutorial can helps me to figure out algorithm and start project.
Usually you will never find the full solution, you will have to merge multiple.
Here ist how I would approach this task (a quick and dirty solution):
Step 1)
Find an Example that solves a part of the problem and work from there
(Based on the example Quadratic Bezier Curve)
Then I :...
I removed the tween
added Mouse Input
split the path in segments
calculate until where the path should be draw
draw path segments
... And slowly adding missing features:
just update path when close enough
just allow move forwards
...
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: {
create: create,
update: update
}
};
var path;
var curve;
var graphics;
var game = new Phaser.Game(config);
var _myMaxPointIndex = 6;
function create() {
graphics = this.add.graphics();
path = { t: 0, vec: new Phaser.Math.Vector2() };
var startPoint = new Phaser.Math.Vector2(100, 500);
var controlPoint1 = new Phaser.Math.Vector2(50, 100);
var endPoint = new Phaser.Math.Vector2(700, 500);
curve = new Phaser.Curves.QuadraticBezier(startPoint, controlPoint1, endPoint);
}
function _myDrawPath(g, points) {
let startPoint = points.shift();
graphics.lineStyle(30, 0x0000ff, 1);
g.beginPath();
g.moveTo(startPoint.x, startPoint.y);
let maxPointsToDraw = _myMaxPointIndex == -1 ? points.length : _myMaxPointIndex + 1;
for (let index = 0; index < maxPointsToDraw; index++) {
const point = points[index];
g.lineTo(point.x, point.y);
}
g.strokePath();
}
function update() {
graphics.clear();
graphics.lineStyle(2, 0x00ff00, 1);
curve.draw(graphics);
// get 20 Point from the Curve (can be more if to jaggy)
let _myPoints = curve.getPoints(20);
_myDrawPath(graphics, _myPoints)
if (this.input.activePointer.isDown) {
// Here I update the Max point that should be draw
let _myMouse = this.input.activePointer.position;
let _myNearestPoint = _myPoints.reduce((p, c, i) => {
let distance = Phaser.Math.Distance.BetweenPoints(_myMouse, c)
if (p.distance == -1 || p.distance > distance) {
p.distance = distance
p.idx = i
}
return p
}, { distance: -1 })
_myMaxPointIndex = _myNearestPoint.idx
}
}
h1 {
font-family:arial
}
#phaser-example{
transform: translate(-20%, -20%) scale(.5);
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
<h1>Click to calculate path</H1>
<div id="phaser-example"></div>
And with a bit of luck:
While building this solution, I had to "google" for some documentation details, and found this in a Phaser forum, that points to a interesting solution with a working CodePen, with a more complex full working example (Just adding the codepen link if the forum entry gets deleted).

PhaserJS: After Rotation of camera dragging a Sprite gives strange coords

Basically the problem is that after you rotate the camera, the points that are given as arguments in the callback for dragging are not what I expected. I'm guessing I have to Rotate the given points also but I just couldn't.
Can Someone explain what is going on, is this some kind of bug or what should I do in order the sprite to follow the mouse cursor?
Easiest way to explain the problem is to reproduce it:
1) Go to Phaser Example Runner
2) Copy- Paste this code:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
function create ()
{
var image = this.add.sprite(200, 300, 'eye').setInteractive();
this.cameras.main.setRotation(Math.PI);
image.on('pointerover', function () {
this.setTint(0x00ff00);
});
image.on('pointerout', function () {
this.clearTint();
});
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject) {
gameObject.setTint(0xff0000);
});
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
console.log(`x: ${dragX}, y: ${dragY}`);
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function (pointer, gameObject) {
gameObject.clearTint();
});
}
3) Open the console, drag around the Eye and look at what coordinates are given.
4) If you remove line 24 (the rotation of the camera) Everything works as expected.
(The example is taken from Phaser 3 Official examples and a bit changed for the bug)
According to Phaser's API Documentation on the setRotation() method, the rotation given in radians applies to everything rendered by the camera. Unfortunately, your pointer isn't rendered by the camera so it doesn't get the same rotated coordinates. Not sure if this is a bug with the library or just a poorly documented exception, but I believe there is a workaround.
Create 2 variables to hold an initial position and a final position:
var image = this.add.sprite(200, 300, 'eye').setInteractive();
var initial = [];
var final = [];
Populate the initial position in your .on('dragstart') method:
this.input.on('dragstart', function (pointer, gameObject) {
initial = [
gameObject.x,
gameObject.y,
pointer.x,
pointer.y
];
gameObject.setTint(0xff0000);
});
Then, populate the final variable in your .on('drag') method:
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
final = [
gameObject.x, // not necessary but keeping for variable shape consistency
gameObject.y, // not necessary but keeping for variable shape consistency
pointer.x,
pointer.y
];
gameObject.x = initial[0] + (initial[2] - final[2]);
gameObject.y = initial[1] + (initial[3] - final[3]);
});
All we're doing here is keeping track of the change in pointer position and mimicking that change in our gameObject.

Bing Maps SpatialMath Module Intersection is not accurate with Multiple pins with same coordinates

I figured an issue, while i have thousands of pins over the map, i am using drawing tool to draw shapes free hand and then executing the Intersection on "drawingEnded" event, While i could see the intersection should return more than it actually returns,
Am i missing something ? For Example, If there are around 500 pins under the new area drawn, Intersection method only returns 100 or few more,
My Spider Cluster Configuration:
` Microsoft.Maps.loadModule(['SpiderClusterManager'], function () {
spiderManager = new SpiderClusterManager(map, pinssame, {
//clusteredPinCallback: function (cluster) {
// //Customize clustered pushpin.
// cluster.setOptions({
// color: 'red',
// icon:'https://www.bingmapsportal.com/Content/images/poi_custom.png'
// });
//},
pinSelected: function (pin, cluster) {
if (cluster) {
showInfobox(cluster.getLocation(), pin);
} else {
showInfobox(pin.getLocation(), pin);
}
},
pinUnselected: function () {
hideInfobox();
},
gridSize: 80
});
});
`
Intersection Function Code which gets triggered after "drawingEnded" event:
` function findIntersectingData(searchArea) {
//Ensure that the search area is a valid polygon, should have 4 Locations in it's ring as it automatically closes.
if (searchArea && searchArea.getLocations().length >= 4) {
//Get all the pushpins from the pinLayer.
//var pins = spiderManager._data;
//Using spatial math find all pushpins that intersect with the drawn search area.
//The returned data is a copy of the intersecting data and not a reference to the original shapes,
//so making edits to them will not cause any updates on the map.
var intersectingPins = Microsoft.Maps.SpatialMath.Geometry.intersection(pins, searchArea);
//The data returned by the intersection function can be null, a single shape, or an array of shapes.
if (intersectingPins) {
//For ease of usem wrap individudal shapes in an array.
if (intersectingPins && !(intersectingPins instanceof Array)) {
intersectingPins = [intersectingPins];
}
var selectedPins = [];
//Loop through and map the intersecting pushpins back to their original pushpins by comparing their coordinates.
for (var j = 0; j < intersectingPins.length; j++) {
for (var i = 0; i < pins.length; i++) {
if (Microsoft.Maps.Location.areEqual(pins[i].getLocation(), intersectingPins[j].getLocation())) {
selectedPins.push(pins[i]);
break;
}
}
}
//Return the pushpins that were selected.
console.log(selectedPins);
return selectedPins;
}
}
return null;
}
`
The function is not returning accurate pin data,
Am i missing something here ?
Any Help Appreciated,
Thanks & Regards,
Shohil Sethia
UPDATE :
Just figured, It is an assumption ,I have multiple pins with same coordinates over the layer, Is this the reason that it returns only pins which intersects with different coordinates over the map ?,
Thanks & Regards,
Shohil Sethia
The method returns objects that represent the intersection, not the exact copies of input shapes. So yes, if multiple pushpins with the same coordinates are within the area, only one pushpin of that coordinates will be in the result, since that alone is good enough as a representation.
You can try the sample below, only one pushpin is returned:
// Creates a polygon of current map bounds
var polygon = new Microsoft.Maps.SpatialMath.locationRectToPolygon(map.getBounds());
// Creates a bunch of the pushpins of the same coordinates(map center)
var pushpin1 = new Microsoft.Maps.Pushpin(map.getCenter());
var pushpin2 = new Microsoft.Maps.Pushpin(map.getCenter());
var pushpin3 = new Microsoft.Maps.Pushpin(map.getCenter());
var pushpin4 = new Microsoft.Maps.Pushpin(map.getCenter());
var pushpin5 = new Microsoft.Maps.Pushpin(map.getCenter());
// Adds the shapes to map for some visualization
map.entities.push([polygon, pushpin1, pushpin2, pushpin3, pushpin4, pushpin5]);
// Only one pushpin is returned as result
var intersectingPin = Microsoft.Maps.SpatialMath.Geometry.intersection([pushpin1, pushpin2, pushpin3, pushpin4, pushpin5], polygon);
Have you checked if the number of results adds up when taking duplicate pins into account?
I got a solution, Since Intersection API ignore multiple pushPins with same coordinates, Therefore there is another API named as contains which takes two parameters which are the shape and the pushpin, and it returns whether it is contained in that shape or not in a boolean form. So true if pushpin is in that shape, and false in the other way.
function findIntersectingData(searchArea) {
//Ensure that the search area is a valid polygon, should have 4 Locations in it's ring as it automatically closes.
if (searchArea && searchArea.getLocations().length >= 4) {
var selectedPins = [];
for (var i = 0; i < pins.length; i++) {
if (Microsoft.Maps.SpatialMath.Geometry.contains(searchArea, pins[i])) {
selectedPins.push(pins[i]);
}
}
//Return the pushpins that were selected.
console.log(selectedPins);
//return updatePrescriberTerr(selectedPins);
return selectedPins;
}
return null;
}
Therefore in the above function the we can loop it from the pushPins array and form the intersection set accordingly based on the boolean values.
Hope it helps to those with similar scenario !
Regards,
Shohil Sethia

Bullet spawn speed or generation speed phaser

Hi all I have a function that generates bullets every time the player touches the screen.
Is there a way that I can limit the amount of bullets generated? Basically if I press the screen very quickly lots of bullets get generated but I would like to limit it to at least i per second instead of 2 or 3 per second.
Below you can find my firing function and my bullet creation function:
createBullets: function(){
//Bullets
this.bullets = this.add.group();
this.bullets.enableBody = true;
this.bullets.physicsBodyType = Phaser.Physics.P2JS;
this.bullets.createMultiple(500, 'bullet', 0, false);
this.bullets.setAll('anchor.x', 0.5);
this.bullets.setAll('anchor.y', 0.5);
this.bullets.setAll('outOfBoundsKill', true);
this.bullets.setAll('checkWorldBounds', true);
},
fireBullet: function(){
this.bullet = this.bullets.getFirstExists(false);
if (this.bullet) {
this.bullet.reset(this.tanque.x, this.tanque.y - 20);
this.bullet.body.velocity.y = -500;
}
},
and my update function:
if(this.input.activePointer.isDown){
if (!this.mouseTouchDown) {
this.touchDown();
}
}else {
if (this.mouseTouchDown) {
this.touchUp();
}
}
Any help I would really appreciate.
One option is to store two values:
nextShotTime: next time a shot can be fired
shotDelay: delay between shots (can be set like Phaser.Timer.SECOND * 2)
I don't see where you're calling fireBullet() in your example code above, but either before you make the call, or within the function, you could then check to see if the nextShotTime is in the past. If it is, fire another bullet and then update the nextShotTime with the current time plus the shotDelay.
For example:
if (this.nextShotTime < this.time.now) {
this.nextShotTime = this.time.now + this.shotDelay;
// add your code that will fire a bullet.
}
I have had similar problems in games before. The solution I used is the same as the one posted above. I found it in this
Phaser tutorial.
The fire function used in the tutorial is:
fire: function() {
if (this.nextShotAt > this.time.now) {
return;
}
this.nextShotAt = this.time.now + this.shotDelay;
You can modify it to suit your purposes.
This is part of a fire function I used in a game I made:
fire: function() {
//Make sure the player can't shoot when dead and that they are able to shoot another bullet
if(!this.player.alive || this.time.now < this.nextFireTime) {
return;
}
this.nextFireTime = this.time.now + this.fireRate;
var bullet;
//If weaponlvl = 0, shoot a normal bullet
if(this.weaponlvl === 0) {
if(this.bullet1.countDead() === 0) {
return;
}
//Properties for the basic weapon
this.fireRate = 500;
bullet = this.bullet1.getFirstExists(false);
bullet.reset(this.player.x, this.player.y-22);
bullet.body.velocity.y = -300;
}
Hope this helps you in some way.

How to get web element (id) from the element position in D3.js force graph

I am working with the D3.js force graph but I am not able to find out the element id from the element position (which I know).
I am using Leap motion. I need to simulate a mouse event (a click, a move, a drag, etc.) without a mouse. And, if I am right, in order to be able to do this, I need to find out what is the the element id from the coordinates x and y (these coordinates I know from the Leap motion pointer). So from what you wrote above, I need to find out the ('.node’).
Here is what I already tried but it did not work:
Is it possible to use non-mouse, non-touch events to interact with a D3.js graph? If so, what is the most efficient way to go about it?
So I used this function (see below), but I need to know the element id to make it work correctly:
//graph.simulate(document.getElementById("r_1"), 'dblclick', {pointerX: posX, pointerY: posY});
//here id r_1 is hardcoded, but I need to find out id from x and y coordinates.
this.simulate = function (element, eventName) {
function extend(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
var eventMatchers = {
'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
'MouseEvents': /^(?:click|dblclick|mouse(?:down|up|over|move|out))$/
};
var defaultOptions = {
pointerX: 0,
pointerY: 0,
button: 0,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
bubbles: true,
cancelable: true
};
var options = extend(defaultOptions, arguments[2] || {});
var oEvent, eventType = null;
for (var name in eventMatchers) {
if (eventMatchers[name].test(eventName)) {
eventType = name;
break;
}
}
if (!eventType)
throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');
if (document.createEvent) {
oEvent = document.createEvent(eventType);
if (eventType == 'HTMLEvents') {
oEvent.initEvent(eventName, options.bubbles, options.cancelable);
}
else {
oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
}
element.dispatchEvent(oEvent);
}
else {
options.clientX = options.pointerX;
options.clientY = options.pointerY;
var evt = document.createEventObject();
oEvent = extend(evt, options);
element.fireEvent('on' + eventName, oEvent);
}
return element;
}
Many thanks for your help and ideas.
If you want access to the element, it's implicit in D3's iterators via this.
d3.selectAll('.node').each(function(d) {
console.log(this); // Logs the element attached to d.
});
If you really need access to the id, you can get it with selection.attr():
d3.selectAll('.node').each(function() {
console.log(d3.select(this).attr('id')); // Logs the id attribute.
});
You don't have to use each. Any of the iterators, such as attr or style, etc., have 'this' as the bound element:
d3.selectAll('.node').style('opacity', function(d) {
console.log(this);// Logs the element attached to d.
});
If you want the x and y coordinates of a node, it's part of the data:
d3.selectAll('.node').each(function(d) {
console.log(d.x, d.y); // Logs the x and y position of the datum.
});
If you really need the node attributes themselves, you can use the attr accessor.
d3.selectAll('.node').each(function(d) {
// Logs the cx and cy attributes of a node.
console.log(d3.select(this).attr('cx'), d3.select(this).attr('cy'));
});
EDIT: It looks like you need an element reference, but the only thing you know about the node in context is its position. One solution is to search through all nodes for a node with matching coordinates.
// Brute force search of all nodes.
function search(root, x, y) {
var found;
function recurse(node) {
if (node.x === x && node.y === y)
found = node;
!found && node.children && node.children.forEach(function(child) {
recurse(child);
});
}
recurse(root);
return found;
}
However this only gives you the node object, not the element itself. You will likely need to store the element references on the nodes:
// Give each node a reference to its dom element.
d3.selectAll('.node').each(function(d) {
d.element = this;
});
With that in place, you should be able to access the element and get its id.
var id, node = search(root, x, y);
if (node) {
id = node.element.getAttribute('id');
}
The brute-force search is fine for a small number of nodes, but if you're pushing a large number of nodes you might want to use D3's quadtree (example) to speed up the search.
Use d3.select('#yourElementId')
For more info check this out: https://github.com/mbostock/d3/wiki/Selections

Resources