here map - add points on polyline to manipulate routing - polyline

I have to create with "here maps" routing with the possibility of manipulating it (eg: add drag on some points on a polyline, move it somewhere, add there next checkpoint, and recalculate the route). I have no problem with clicking on polyline and get coordination of new checkpoint. I know, more or less, how to add drag and drop to it. But however I try, I can't add new point on polyline.
I try to get something like that: https://wego.here.com/directions/drive/ulica-Kolejarzy,-44-102-Gliwice,-Poland:loc-dmVyc2lvbj0xO3RpdGxlPXVsaWNhK0tvbGVqYXJ6eTtsYW5nPXBsO2xhdD01MC4zMDYwNDtsb249MTguNjkwNztzdHJlZXQ9dWxpY2ErS29sZWphcnp5O2NpdHk9R2xpd2ljZTtwb3N0YWxDb2RlPTQ0LTEwMjtjb3VudHJ5PVBPTDtkaXN0cmljdD1HbGl3aWNlO3N0YXRlPVdvai4rJUM1JTlBbCVDNCU4NXNraWU7Y291bnR5PUdsaXdpY2U7Y2F0ZWdvcnlJZD1zdHJlZXQtc3F1YXJlO3NvdXJjZVN5c3RlbT1pbnRlcm5hbDtwZHNDYXRlZ29yeUlkPTkwMC05NDAwLTA0MDE/ulica-Mostowa,-43-600-Jaworzno,-Poland:loc-dmVyc2lvbj0xO3RpdGxlPXVsaWNhK01vc3Rvd2E7bGFuZz1wbDtsYXQ9NTAuMjA3Njk7bG9uPTE5LjI1NTc0O3N0cmVldD11bGljYStNb3N0b3dhO2NpdHk9SmF3b3J6bm87cG9zdGFsQ29kZT00My02MDA7Y291bnRyeT1QT0w7ZGlzdHJpY3Q9SmF3b3J6bm87c3RhdGU9V29qLislQzUlOUFsJUM0JTg1c2tpZTtjb3VudHk9SmF3b3J6bm87Y2F0ZWdvcnlJZD1zdHJlZXQtc3F1YXJlO3NvdXJjZVN5c3RlbT1pbnRlcm5hbDtwZHNDYXRlZ29yeUlkPTkwMC05NDAwLTA0MDE?map=50.25857,18.97158,11,normal . You know, thwn you can drag and drop this polyline and add more checkpoints
Belowe I put my code with some comments. There is method "manipulatePolylineOnClick" there I got new coordinates by click and want to add it to polyline. But I really don't know how.
export function createRoute(origin, destination, via, platform, map) {
let routingParameters = {
'routingMode': 'fast',
'transportMode': 'truck',
'return': 'polyline'
};
setRoutingParameters(routingParameters, origin, destination, via)
var router = platform.getRoutingService(null, 8);
var onResult = function (result) {
if (result.routes.length) {
result.routes[0].sections.forEach((section) => {
//create polyline
let linestring = H.geo.LineString.fromFlexiblePolyline(section.polyline);
let routeLine = new H.map.Polyline(linestring, {
style: {strokeColor: 'red', lineWidth: 3}
});
// needed to polyline drag and drop
let verticeGroup = new H.map.Group({
visibility: false
});
let mainGroup = new H.map.Group({
volatility: true, // mark the group as volatile for smooth dragging of all it's objects
objects: [routeLine, verticeGroup]
});
let polylineTimeout;
routeLine.draggable = true;
//my method that should add poitnts to manimupate route, and allow to do it
manipulatePolylineOnClick(routeLine, map, verticeGroup)
let startMarker = new H.map.Marker(section.departure.place.location);
let endMarker = new H.map.Marker(section.arrival.place.location);
map.addObjects([routeLine, startMarker, endMarker]);
map.getViewModel().setLookAtData({bounds: routeLine.getBoundingBox()});
});
}
};
router.calculateRoute(routingParameters, onResult,
function(error) {
alert(error.message);
});
}
function setRoutingParameters(routingParameters, origin, destination, via) {
routingParameters['origin'] = origin
routingParameters['destination'] = destination
}
function manipulatePolylineOnClick(polyline, map, verticeGroup) {
const svgCircle = '<svg width="20" height="20" version="1.1" xmlns="http://www.w3.org/2000/svg">' +
'<circle cx="10" cy="10" r="7" fill="transparent" stroke="red" stroke-width="4"/>' +
'</svg>';
// so, I have new coordinates on click in coord variable. But what I have to do, to add it to polyline?
polyline.addEventListener('tap', function (e) {
let coord = map.screenToGeo(e.currentPointer.viewportX, e.currentPointer.viewportY);
//it's not working
let vertice = new H.map.Marker(
coord,
{
icon: new H.map.Icon(svgCircle, {anchor: {x: 20, y: 20}})
}
);
vertice.draggable = true;
// vertice.setData({'verticeIndex': index})
verticeGroup.addObject(vertice);
console.log('coord', coord)
})
}

Related

How do I draw a marker or a circle on a Google StreetViewPanorama

I am creating a walkthrough for the interior of a building and am wondering how to draw a marker on a StreetViewPanorama. Maybe I'm missing something basic, but everything I have read indicates that you need a lat and lng to draw the marker.
Here is what I have:
var initPosPanoID, streetView;
function initPano() {
// Set StreetView provider.
var streetViewOptions = {
zoom: 0,
panoProvider: getCustomPanorama,
pano : "lobby",
addressControlOptions: {
position: google.maps.ControlPosition.BOTTOM_CENTER
}
};
// Create a StreetView object.
var streetViewDiv = document.getElementById('map');
streetView = new google.maps.StreetViewPanorama(streetViewDiv, streetViewOptions);
// Add links when it happens "links_change" event.
google.maps.event.addListener(streetView, "links_changed", createCustomLink);
google.maps.event.addListener(streetView, "pano_changed", function() {
var panoCell = document.getElementById('pano-cell');
panoCell.innerHTML = panorama.getPano();
});
}
function getCustomPanoramaTileUrl(panoID, zoom, tileX, tileY) {
// Return a pano image given the panoID.
return "images/he/" + panoID + '.jpg';
}
function getHeading(panoID) {
var heading;
switch(panoID) {
case "lobby":
heading = 0;
break;
case "secorner":
heading = 100;
break;
}
return heading;
}
function getCustomPanorama(panoID) {
// get a custom heading for the pano
var heading = getHeading(panoID);
var streetViewPanoramaData = {
links: [],
copyright: 'Imagery (c) HumanElement',
tiles: {
tileSize : new google.maps.Size(1024, 512),
worldSize : new google.maps.Size(1024, 512),
// The heading in degrees at the origin of the panorama
// tile set.
centerHeading : heading,
getTileUrl : getCustomPanoramaTileUrl
}
};
switch(panoID) {
case "lobby":
// Description of this point.
streetViewPanoramaData["location"] = {
pano: 'lobby',
description: "Human Element",
latLng: new google.maps.LatLng(42.282138, -83.751471)
};
return streetViewPanoramaData;
case "secorner":
streetViewPanoramaData["location"] = {
pano: 'secorner',
description: "SouthEast Corner",
latLng: new google.maps.LatLng(42.282078, -83.751413)
};
return streetViewPanoramaData;
}
}
function createCustomLink() {
var links = streetView.getLinks();
var panoID = streetView.getPano();
switch(panoID) {
case "lobby":
links.push({
description : "SouthEast Corner",
pano : "secorner",
heading : 280
});
break;
case "secorner":
links.push({
description : "HumanElement Lobby",
pano : "lobby",
heading : 90
});
break;
}
}
I would like to have different markers or touchpoints at different locations, but am not sure how to get them on there.
Trying to draw a standard marker does not work without the lat/lng.
I thought about trying to create it around a google.maps.Point thinking I might be able to use the x and y from my tiles, but couldn't seem to get that working.
The other options I see are related to google.maps.drawing.DrawingManager.
Does anyone have any advice on this?
Setting up the map this way helped: It creates the map and panorama separately and then sets the panorama into the map, rather than just having the panorama object by itself.
map = new google.maps.Map(document.getElementById('map'), {
center: position,
zoom: 10
});
// Create the panorama and set it into the map
panorama = new google.maps.StreetViewPanorama(
document.getElementById('map'), {
position: position,
pov: {
heading: 0,
pitch: -10
},
// Override the default panoId to outside the building to start
pano:'e_giRekRylYAAAQn7y2xAg'
});
map.setStreetView(panorama);
For placing markers on the map, I found an excellent plugin which creates points and then places elements on those points.
https://github.com/marmat/google-maps-api-addons/tree/master/panomarker
So far this is working very well. If you have an interior walkthrough, you should be able to toggle markers based on the PanoId. You can even add click listeners to open up dialogs.

AmCharts map - insert html

I'm trying to create a pulse effect on a point on a AmCharts Map. In order to do this I need to insert HTML at a latitude and longitude point but can't work out how to do it through the api (http://docs.amcharts.com/3/javascriptmaps/)
Here is the effect I'm trying to achieve - http://kevinurrutia.tumblr.com/post/16411271583/creating-a-css3-pulsating-circle
Here is a jsfiddle of the map with the HTML and CSS http://jsfiddle.net/9cBXh/2/
// request #3275
var dataPoints = [{
latitude: '51.000000000000',
longitude: '9.000000000000',
type: 'bubble',
color: '#cc0000',
fixedSize: false,
alpha: 0.9,
height: 30,
width: 30,
centered: true,
id: 'test'
}];
AmCharts.ready(function() {
// create AmMap object
var map = new AmCharts.AmMap();
// set path to images
map.pathToImages = "http://www.ammap.com/lib/images/";
var dataProvider = {
mapVar: AmCharts.maps.worldLow,
getAreasFromMap:false,
images: dataPoints
};
// pass data provider to the map object
map.dataProvider = dataProvider;
map.areasSettings = {
autoZoom: true,
selectedColor: "#CC0000"
};
// write the map to container div
map.write("mapdiv");
});
The red dot is the bubble generated through the api. The blue dot and circle is the html I need to insert at the lat and long co-ordinates...somehow!
Any help would be appreciated.
Here's a complete working example of the AmCharts map with several pulsating HTML elements as map markers:
http://www.amcharts.com/demos/custom-html-elements-map-markers/
(You can view the source by clicking on the EDIT button)
The idea is very simple:
Trap "positionChanged" event. Go throiugh all of the "images" in the map's dataProvider, create HTML elements for each of those, then position them directly over the map by using API functions that resolve longitude/latitude coordinates to screen top/left coordinates:
// add events to recalculate map position when the map is moved or zoomed
map.addListener("positionChanged", updateCustomMarkers);
// this function will take current images on the map and create HTML elements for them
function updateCustomMarkers (event) {
// get map object
var map = event.chart;
// go through all of the images
for( var x in map.dataProvider.images) {
// get MapImage object
var image = map.dataProvider.images[x];
// check if it has corresponding HTML element
if ('undefined' == typeof image.externalElement)
image.externalElement = createCustomMarker(image);
// reposition the element accoridng to coordinates
image.externalElement.style.top = map.latitudeToY(image.latitude) + 'px';
image.externalElement.style.left = map.longitudeToX(image.longitude) + 'px';
}
}
// this function creates and returns a new marker element
function createCustomMarker(image) {
// create holder
var holder = document.createElement('div');
holder.className = 'map-marker';
holder.title = image.title;
holder.style.position = 'absolute';
// create dot
var dot = document.createElement('div');
dot.className = 'dot';
holder.appendChild(dot);
// create pulse
var pulse = document.createElement('div');
pulse.className = 'pulse';
holder.appendChild(pulse);
// append the marker to the map container
image.chart.chartDiv.appendChild(holder);
return holder;
}

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);

Click Listeners in Loop - Array and Closure

I realise I'm treading on thin ice opening another closure issue, but I have searched and can't find an answer to my issue. I have a Google Maps API v3 page which generates two maps from one block of code - a small map centered on the user's current location and a larger map showing the whole area with the user's location marked where it is, center or not. On top of the map is a rectangle layer consisting of 14 rectangles. In order to generate the two maps, I have had to put the rectangles in a 2 dimensional array, rectangles[1] for 'map', and rectangles[2] for 'map2':
var rectangles = [0,1,2,3,4,5,6,7,8,9,10,11,12,13];
rectangles[1][0]=new google.maps.Rectangle({
bounds:new google.maps.LatLngBounds(new google.maps.LatLng(a, b), new google.maps.LatLng(x, y)),
map:map,
fillColor:'red',
fillOpacity: 0.3,
strokeOpacity: 0,
url: 'http://example.com',
clickable: true
});
rectangles[2][0]=new google.maps.Rectangle({
bounds:new google.maps.LatLngBounds(new google.maps.LatLng(a, b), new google.maps.LatLng(x, y)),
map:map2,
fillColor:'red',
fillOpacity: 0.3,
strokeOpacity: 0,
url: 'http://example.com',
clickable: true
});
...and so on. It all works fine and the two maps are displayed and the geolocation works. Now I want to add a click listener for each rectangle but I'm not sure who to reference the array. This is what I have now:
for ( i = 0; i < rectangles[1].length; i++ ){
google.maps.event.addListener(rectangles[1][i], 'click', function() {
window.location.href = this.url;
});
}
for ( x = 0; x < rectangles[2].length; x++ ){
google.maps.event.addListener(rectangles[2][x], 'click', function() {
window.location.href = this.url;
});
}
Which obviously won't work. I have seen various solutions to the closure issue, but I'm not sure I'm even heading in the right direction in referencing the two arrays of rectangles - or if I even need to define two different sets of click listeners. I'd be really grateful if someone could point me in the right direction - and sorry if this is just going over old ground that appears obvious. There's always a new learner coming along who is trying hard to catch up.
Thanks.
//First, set up `rectangles` as an array containing two arrays.
var rectangles = [];
rectangles[0] = [];
rectangles[1] = [];
//As `google.maps.Rectangle` doesn't accept a `url` option,
//its url needs to be defined separately from the rectangle itself,
//but in such a way that the two are associated with each other.
//For this we can use a javascript plain object.
rectangles[0][0] = {
rect: new google.maps.Rectangle({
bounds: new google.maps.LatLngBounds(new google.maps.LatLng(a, b), new google.maps.LatLng(x, y)),
map: map,
fillColor: 'red',
fillOpacity: 0.3,
strokeOpacity: 0,
clickable: true
}),
url: 'http://example.com'
};
rectangles[1][0] = new google.maps.Rectangle({
...
});
rectangles[0][1] = new google.maps.Rectangle({
...
});
rectangles[1][1] = new google.maps.Rectangle({
...
});
rectangles[0][2] = new google.maps.Rectangle({
...
});
rectangles[1][2] = new google.maps.Rectangle({
...
});
//Now to attach the click listeners.
//First we define a function that adds a click listener.
//By doing this in its own function, a closure is formed,
//trapping the formal variable `rectObj` and making `rectObj.url`
//accessible to the listener when it is called in response to future clicks.
function addClickListener(rectObj) {
google.maps.event.addListener(rectObj.rect, 'click', function() {
window.location.href = rectObj.url;
});
}
//Now, we can loop through the `rectangles` arrays, adding listeners.
for ( i = 0; i < 2; i++ ) {
for ( j = 0; j < 14; j++ ) {
if(rectangles[i][j]) {//safety
addClickListener(rectangles[i][j]);
}
}
}

Resources