I'm using OpenLayers with Waze (Maps layers) and having some problems with variables not propagating.
I've got this code:
var lonlat = new Array(), infodiv = new Array();
for (var i = 0; i < stations.length; i++)
{
if (i == 0)
icon_temp = icon;
else
icon_temp = icon.clone();
lonlat[i] = new OpenLayers.LonLat(stations[i].lon,stations[i].lat);
infodiv[i] = "<div style='font-size: 14px;'><strong>" + stations[i].company + "</strong></div>";
marker = new OpenLayers.Marker(lonlat[i],icon_temp);
marker.setOpacity(0.8);
marker.events.register('mousedown', marker, function(evt) {
popup = new OpenLayers.Popup.FramedCloud(null,
lonlat[i],
null,
infodiv[i],
anchor=null,true,null);
map.addPopup(popup);
OpenLayers.Event.stop(evt);
});
markers.addMarker(marker);
}
The code should iterate through the 'stations' array and add markers to the map. It works just fine!
The problem is with the 'lonlat' and 'infodiv' arrays. The 'OpenLayers.Popup.FramedCloud' doesn't see them - it is returned null (checked using FireBug). If I lose the array and only assign each time lonlat = ... and infodiv = ... like this:
for (var i = 0; i < stations.length; i++)
{
if (i == 0)
icon_temp = icon;
else
icon_temp = icon.clone();
lonlat = new OpenLayers.LonLat(stations[i].lon,stations[i].lat);
infodiv = "<div style='font-size: 14px;'><strong>" + stations[i].company + "</strong></div>";
marker = new OpenLayers.Marker(lonlat,icon_temp);
marker.setOpacity(0.8);
marker.events.register('mousedown', marker, function(evt) {
popup = new OpenLayers.Popup.FramedCloud(null,
lonlat,
null,
infodiv,
anchor=null,true,null);
map.addPopup(popup);
OpenLayers.Event.stop(evt);
});
markers.addMarker(marker);
}
it is being propagated to the FrameCloud function and is being shown - but then the problem is it shows only the last lonlat and infodiv (it's like it doesn't hold a copy of them but holds the actual objects - so every iteration 'lonlat' and 'infodiv' are being replaced by the latest info).
How can this be overcome?
This is due to closure of variable i.
Introduce another scope like,
(function(i){
marker.events.register('mousedown', marker, function(evt) {
popup = new OpenLayers.Popup.FramedCloud(null,
lonlat[i],
null,
infodiv[i],
anchor=null,true,null);
map.addPopup(popup);
OpenLayers.Event.stop(evt);
});
})(i);
Related
I am new to scripting on photoshop and it seems not all javascript is the same. What I'm trying to do is I have a list of layers that are as follows:
Cat pic 1.jpg
Cat pic 1.jpg copy
Dog pic 1.jpg
Dog pic 1.jpg copy
....
I want to merge the ones that are copies of each other so "Cat pic 1.jpg" and "Cat pic 1.jpg copy" and create one layer from the two which is just "Cat pic 1.jpg".
They are all active and there is no shapes or anything so its just layers. I have about 300 layers and each one is exactly like that. There is a duplicate of each layer and the name has copy at the end. I wrote a script but I don't know how to merge two layers together. My code doesn't work. It is pieced together from someone trying to sort the layers alphabetically.
Basically I had a layer list and I flipped it horizontally and now I need to merge the left half with the right half. The left is without the word 'copy'.
Any help is greatly appreciated guys! Please feel free to ignore all my code I have zero confidence in it.
Thanks in advance!
#target photoshop
var layers = activeDocument.layers;
var layersArray = [];
var len = layers.length;
// store all layers in an array
for (var i = 0; i < len; i++) {
layersArray.push(layers[i]);
}
var layersOrig= [];
for (var i = 0; i < len; i++) {
var cond = myIndexOf(layersArray[i], "copy");
if (cond === -1) {
layersOrig.push(layersArray[i]);
delete layersArray[i];
}
}
layersOrig.sort();
// sort layer top to bottom
layersArray.sort();
for (var i = 0; i < len; i++) {
layersArray[i] = merge(layersOrig[i], layersArray[i];
}
for (i = 0; i < len; i++) {
layersArray[i].move(layers[i], ElementPlacement.PLACEBEFORE);
}
function myIndexOf(array, x){
var n=-1, N=array.length;
while (++n<N && array[n]!==x);
return n<N ? n : -1;
};
Maybe like this?
function main()
{
var layersInfo = getAllLayersNames(); //getting myself an object of layer names and IDs
for (layerName in layersInfo)
{
deselectLayers(); //deselecting all layers first
if (layersInfo[layerName].length == 1) continue; //if there's only one layer in the object: ignore it
for (var i = 0; i < layersInfo[layerName].length; i++)
{
selectById(layersInfo[layerName][i], true); //selecting layers-clones by IDs
}
mergeDown(); //merge down selected layers
activeDocument.activeLayer.name = layerName; //renaming the resulting layer to original layer name
}
/////////////////////////////////////////////////////////////////////////////////////
// functions
function getAllLayersNames()
{
var lyrs = {};
try
{
activeDocument.backgroundLayer;
var layers = 0
}
catch (e)
{
var layers = 1;
};
while (true)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), layers);
try
{
var desc = executeActionGet(ref);
}
catch (err)
{
break;
}
var lyr = {};
lyr.name = desc.getString(charIDToTypeID("Nm "));
var nameWithoutCopy = lyr.name.replace(/\scopy.*/, '');
lyr.id = desc.getInteger(stringIDToTypeID("layerID"));
if (lyrs[nameWithoutCopy] == undefined) lyrs[nameWithoutCopy] = [lyr.id]
else lyrs[nameWithoutCopy].push(lyr.id);
layers++;
}
return lyrs
};
function selectById(id, add)
{
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putIdentifier(charIDToTypeID('Lyr '), id);
desc1.putReference(charIDToTypeID('null'), ref1);
if (add) desc1.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
};
function deselectLayers()
{
var desc60 = new ActionDescriptor();
var ref30 = new ActionReference();
ref30.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc60.putReference(charIDToTypeID('null'), ref30);
executeAction(stringIDToTypeID('selectNoLayers'), desc60, DialogModes.NO);
};
function mergeDown()
{
var desc11 = new ActionDescriptor();
executeAction(charIDToTypeID('Mrg2'), desc11, DialogModes.NO);
};
}
app.activeDocument.suspendHistory("rename all copies", "main()");
Input > Result:
I've got real time gps positions for a few cars and I want to create a map with updating markers. My code works but it doesn't "update" the markers, instead it adds new objects with new coordinates to the leaflet map. After few minutes my map is full of markers. What I'm doing wrong? Here is my basic concept.
var intervalV = document.getElementById("intervalValue").value * 1000;
document.getElementById("setIntervalButton").onclick = startData;
function startData() {
DataInterval = window.setInterval(getNewData, intervalV);
};
function getNewData() {
$.getJSON(server, {
fun : "GetGpsData",
userId : "user",
sessionId : $("#sessionId").val()
}, fillMap);
}
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var positions = json.devicesData[i].positions.length;
var devicepostiion;
if (json.devicesData[i].connected == false
) {
var devicepostion = L.marker([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon], {
icon : offlineCarIcon
}, {
draggable : false
}).addTo(map);
} else {
devicepostion = new L.marker(, {
icon : onlineCarIcon
});
devicepostion.addTo(map).setLatLng([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon]).update();
}
}
}
};
If your goal is to update markers with a new visual appearance and location if they already exist on the map...then you should be using .setIcon and .setLatLng on the existing marker instead of making a new one.
Your current code makes new markers in both cases.
Here your code updated to work as you want. As #snkashis pointed out, you do not need to create a new marker each time
var devicePosition = -1;
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (devicePosition === -1) {
var devicePosition = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition.setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition !== -1) {
devicePosition.setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}
If you have multiple markers, you need to update each one accordingly to their id, I suggest to find (or add, if you create the APIs) an unique ID in json.devicesData[i].
Let's suppose the uniqueId of each marker is called, well, uniqueId, then your code can be something like this:
var devicePosition = {};
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
var uniqueId = data.uniqueId;
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (!devicePosition[uniqueId]) {
var devicePosition[uniqueId] = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition[uniqueId].setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition[uniqueId]) {
devicePosition[uniqueId].setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}
I am trying to save on localstorage the markers that I create on click in leaflet and delete them using a button. The problem is that I don't know how to delete just one marker at time and remove them from the main layer without affecting the others.
I want to add a unique id to each marker created (that's why the "Marker #") and later on delete see if the current marker's id or location (lat,lng) match the one stored on localstorage, then delete it from the localstorage and remove it from the main layer.
Anyone could help me solve this? This is giving me headaches!
I am using this function to add them on the map and in localstorage:
initUserLayerGroup();
map.on('click', onMapClick);
var groupUser;
function initUserLayerGroup() {
if (localStorage.userMarkers !== undefined) {
var storageMarkers = [];
var markersUser = [];
storageMarkers = JSON.parse(localStorage.userMarkers);
for (var i = 0; i < storageMarkers.length; i++) {
var x = storageMarkers[i].coords.x;
var y = storageMarkers[i].coords.y;
var name = storageMarkers[i].name;
var marker = L.marker([y, x]).bindPopup(name + "<br><a href='#' class='delete'>Delete</a>");
marker.on("popupopen", onPopupOpen);
markersUser.push(marker);
}
groupUser = L.layerGroup(markersUser);
map.addLayer(groupUser);
}
}
function onMapClick(e) {
var storageMarkers = [];
var markersUser = [];
if (localStorage.userMarkers !== undefined) {
storageMarkers = JSON.parse(localStorage.userMarkers);
}
storageMarkers.push({
"coords": {
"x": e.latlng.lng,
"y": e.latlng.lat
},
"name": "Marker #"
});
var x = storageMarkers[storageMarkers.length -1].coords.x;
var y = storageMarkers[storageMarkers.length -1].coords.y;
var name = storageMarkers[storageMarkers.length -1].name;
var marker = L.marker([y, x]).bindPopup(name + "<br>X: "+ x +", Y: "+ y +"<br><a href='#' class='delete'>Delete</a>");
marker.on("popupopen", onPopupOpen);
markersUser.push(marker);
groupUser = L.layerGroup(markersUser);
map.addLayer(groupUser);
localStorage.userMarkers = JSON.stringify(storageMarkers);
}
function onPopupOpen() {
var tempMarker = this.getLatLng();
$('.delete').click(function() {
localStorage.removeItem('userMarkers');
map.removeLayer(groupUser);
});
}
You can see it working here:
http://plnkr.co/edit/vYDExBBqy9zCGBRZJ944?p=preview
One way is to iterate over the saved array of coordinates in localStorage when the marker is clicked and compare them with the coordinates of the clicked marker. Once they are the same, delete this item from localSotrage and update it.
function onPopupOpen() {
var _this = this;
var clickedMarkerCoords = this.getLatLng();
$('.delete').click(function() {
storageMarkers = JSON.parse(localStorage.userMarkers);
for(i = storageMarkers.length; i > 0; i--) {
if (typeof storageMarkers[i] != 'undefined' &&
(clickedMarkerCoords.lat == storageMarkers[i].coords.y &&
clickedMarkerCoords.lng == storageMarkers[i].coords.x)
) {
storageMarkers.splice(i, 1);
localStorage.userMarkers = JSON.stringify(storageMarkers);
}
}
map.removeLayer(_this);
});
}
Here is the plunker: http://plnkr.co/edit/1xVZjKC1184dfuOlGqVX?p=preview
I'm trying to get this behavior with gmaps4rails :
User clicks link in the sidebar, corresponding marker on the map changes image/color in order to make the selected one stand out from the others.
I've tried with this code
Gmaps.map.callback = function(){
var len = Gmaps.map.markers.length;
for(var i = 0; i < len; i++){
marker = Gmaps.map.markers[i];
google.maps.event.addListener(marker.serviceObject, 'click', (function(i){
return function(){
console.log($(Gmaps.map.markers[i].serviceObject.ne.ga).attr("src", "/assets/marker_sprite2.png"));
}
})(i));
}
}
But this changes every marker's appearance, which is not very useful for what I'm trying to do !
Is there anyway to achieve this ?
EDIT : Made it work see answer below
EDIT 2 : While this solution worked for what I wanted, I stumbled upon an other issue with this method, see comment to answer below
You've a javascript issue. Actually, you can't make a closure with a changing counter: it will always be referenced with it's last value.
Gmaps.map.callback = function(){
for(var i = 0; i < Gmaps.map.markers.length; i++){
marker = Gmaps.map.markers[i];
google.maps.event.addListener(marker.serviceObject, 'click',
(function(marker){
return function(){
console.log($(marker.serviceObject.ne.ga).attr("src", "/assets/marker_sprite2.png"));
}
})(marker)
)
}
}
Your main issue is a bit long, not complex but long. The idea is the following:
add an id to each marker, you could use the block argument of the to_gmaps4rails method and add some more json
create the sidebar yourself and add the id to each line to know which marker you want when you click the li
loop all markers to get the one with the proper id
change it's picture
I made it work with this code :
Gmaps.map.callback = function(e){
var len = Gmaps.map.markers.length;
var markers = Gmaps.map.markers;
for(var i = 0; i < len; i++){
m = Gmaps.map.markers[i];
google.maps.event.addListener(m.serviceObject, 'click',
(function(m, markers){
return function(){
for(a in markers){
markers[a].serviceObject.setIcon("/assets/marker_sprite.png");
}
m.serviceObject.setIcon("/assets/marker_sprite2.png");
}
}(m, markers))
)
}
}
What's happening is we add a click listener to each marker and pass to this listener function the marker itself. I also pass in the whole markers array to reset them all on each click and then make the one I'm interested stand out. This is the simple version, my final version gives this :
Gmaps.map.callback = function(){
var len = Gmaps.map.markers.length;
var markers = Gmaps.map.markers;
var anchor = new google.maps.Point(9.5, 34);
var sAnchor = new google.maps.Point(0, 34);
var origin = new google.maps.Point(0, 0);
var sOrigin = new google.maps.Point(28.5, 0);
var size = new google.maps.Size(28.5,34);
var markerNormal = new google.maps.MarkerImage("/assets/marker_sprite.png", size, origin, anchor);
var markerHighlight = new google.maps.MarkerImage("/assets/marker_sprite_bleu.png", size, origin, anchor);
var shadow = new google.maps.MarkerImage("/assets/marker_sprite.png", size, sOrigin, sAnchor);
for(var i = 0; i < len; i++){
m = Gmaps.map.markers[i];
google.maps.event.addListener(m.serviceObject, 'click',
(function(m, markers){
return function(){
console.log(m);
for(a in markers){
markers[a].serviceObject.setIcon(markerNormal);
markers[a].serviceObject.setZIndex(1);
markers[a].serviceObject.shadow = shadow;
}
Gmaps.map.map.setZoom(7);
m.serviceObject.setZIndex(99);
m.serviceObject.setIcon(markerHighlight);
}
}(m, markers))
)
}
}
If you see anything that could be improved feel free to comment :)
I'm tryng to create a route planner to track my running routes. Using Bing Maps, I am able to create the route, but I'm struggling to remove to default 'beginning', 'end' and 'red circle' itinery icons.
Below is my code so far (based on this link). All I basically want is my own start icon at the beginning of the route and my end icon at the end. I don't need anything else in between apart from the route line.
Any help (along with code improvement tips) gratefully received!
jQuery(function() {
GetMap();
$("#btnStartRoute").click(function() {
map.AttachEvent('onclick', StartRouting);
});
});
var map = null;
var myRoute = [];
var noOfPushPins = 0;
function GetMap() {
map = new VEMap('mapContent');
map.SetCredentials("xxxxxxxxxxxxxxxxxx");
map.LoadMap();
}
function StartRouting(e) {
var xPoint = e.mapX, yPoint = e.mapY;
var pixel = new VEPixel(xPoint, yPoint);
var LL = map.PixelToLatLong(pixel);
cornerOne = LL; //cornerOne is a global level var
var latitude = map.PixelToLatLong(pixel).Latitude;
var longitiude = map.PixelToLatLong(pixel).Longitude;
myRoute[noOfPushPins] = new VELatLong(latitude, longitiude);
noOfPushPins++;
GetRoute();
}
function GetRoute() {
var myRouteOptions = new VERouteOptions();
myRouteOptions.RouteMode = VERouteMode.Walking;
myRouteOptions.RouteColor = new VEColor(0, 102, 51, .7);
myRouteOptions.RouteCallback = RouteCallback;
map.GetDirections(myRoute, myRouteOptions);
}
function RouteCallback(route) {
var myRouteShapes = [];
var myRoutePoints = [];
var points = route.RouteLegs[0].Itinerary.Items;
$.each(points, function(i) {
var routePointCoordinates = new VELatLong(route.RouteLegs[0].Itinerary.Items[i].LatLong.Latitude, route.RouteLegs[0].Itinerary.Items[i].LatLong.Longitude);
var routePointShape = new VEShape(VEShapeType.Pushpin, routePointCoordinates);
if (i != 0) {
routePointShape.SetCustomIcon("<img id='pushPin" + noOfPushPins + "' class='pushPin' src='/Content/Images/Maps/pushPinEnd.gif'><span class='pushPinText'>" + (noOfPushPins + 1) + "</span>");
} else {
routePointShape.SetCustomIcon("<img id='pushPin" + noOfPushPins + "' class='pushPin' src='/Content/Images/Maps/pushPinStart.gif'><span class='pushPinText'>" + (noOfPushPins + 1) + "</span>");
}
myRoutePoints.push(routePointShape);
map.Clear();
map.DeleteRoute();
map.AddShape(myRoutePoints);
});
}
There's an un-documented property called "Shape" on the Itinerary object. You can hide it...
More info here: http://social.msdn.microsoft.com/Forums/en/vemapcontroldev/thread/430449d0-fde4-4adb-9132-248fa6f9db65