2

I am struggling for a bit now with this interaction and finding the right solution on that matter is a quite difficult task (for now).

So, I have created map with some basic points using GeoJSON format (created with PHP & MySQL.). And I'm wondering, is it possible to show rednered points in seperated div element, outside map?

Example:

enter image description here

My question is this? Is it possible when I click on list from right side to automatically open that same clicked element on map? (as shown on picture above)?

Here is code that I'm using to generate map and GeoJSON but that only generates points on map panel.

var karta = L.tileLayer.wms("http://geoportal.dgu.hr/wms?", {
        layers: 'DOF', // možemo još dodati slojeve za 'TK25', 'DOF', 'HOK'
        attribution: "http://geoportal.dgu.hr/ "
});

rasvjeta_kvar_hum = new L.geoJson(null, {
  pointToLayer: function (feature, latlng) {
  return L.marker(latlng, {
    icon: L.icon({
        iconUrl: "img/poweroutage_1.png",
        iconSize: [20, 28],
        iconAnchor: [12, 28],
        popupAnchor: [0, -25]
      })
  });
},
onEachFeature: function (feature, layer) {
if (feature.properties) {
  var content = "<table class='table table-striped table-bordered table-condensed'>" + "<tr><th>Šifra trafostanice</th><td>" + feature.properties.ts_sifra + 
      "</td></tr>" + "<tr><th>Naziv trafostanice</th><td>" + feature.properties.ts_naziv + "</td></tr>" +  
      "<tr><th>Kod lampe</th><td>" + feature.properties.sifra_lampe + "</td></tr>" +
      "<tr><th>Tip/snaga lampe</th><td>" + feature.properties.tip_lampe + "</td></tr>" +
      "<tr><th>Vrsta stupa</th><td>" + feature.properties.vrsta_stupa + "</td></tr>" +
      "<tr><th>Naziv naselja</th><td>" + feature.properties.naziv_naselja + "</td></tr>" +
      "<tr><th>Adresa</th><td>" + feature.properties.adresa + "</td></tr>" 
      "</table>";
layer.bindPopup(content);}}
});

$.getJSON("php/rasvjeta_kvar.php", function (data) {
    rasvjeta_kvar_hum.addData(data);
  });


var map = L.map('map', {
    center: [46.205481, 15.666011],
    zoom: 14,
    layers: [karta, rasvjeta_kvar_hum]
  });

var baseLayers = {
    "Podloga": karta
  };

  var overlays = {
    "Rasvjetna tijela": rasvjeta_kvar_hum
  };

  L.control.layers(baseLayers, overlays,{
    collapsed: false
  }).addTo(map);

I've be trying to resolve my issue following this answer but for now without any luck.

Some guidance or pointers would be highly appreciative, thank you.

UPDATE

Let's say that I'm one step closer (but still pretty far) for completing my task.

enter image description here

Using code below I've have successfully created elements in right panel but with some limitations.

// Create or retrieve the data
var DOF = L.tileLayer.wms(" http://geoportal.dgu.hr/wms?", {
    layers: 'DOF'
});

let people = [
    {
      name: 'FIRST POINT',
      latLng: [46.210888, 15.647540],
      id: '2342fc7'
    },
    {
      name: 'SECOND POINT',
      latLng: [46.211888, 15.647540],
      id: 'djf3892'
    },
    {
      name: 'THIRD POINT',
      latLng: [46.2120888, 15.647540],
      id: '2837hf3'
    }
];

// Create the group
let group = L.layerGroup(),
    list = document.getElementById('list')

// Create the map
var map = L.map('map',{
        center:[46.15796, 15.75336],
        zoom:13,
        layers: DOF
        });


// Loop through the data
people.forEach(person => {
  let marker = L.marker(person.latLng, {
    icon: L.icon({
        iconUrl: "img/power_green.png",
        iconSize: [20, 28],
        iconAnchor: [12, 28],
        popupAnchor: [0, -25]
      }),
        title: person.name,
        riseOnHover: true
      });

  // Add each marker to the group
  group.addLayer( marker );

  // Save the ID of the marker with it's data
  person.marker_id = group.getLayerId(marker);
})

// Add the group to the map
group.addTo(map);

// Click handler for handling
function onClick(data) {
  let { marker_id } = data,
      marker = group.getLayer(marker_id);

  map.panTo( marker.getLatLng() );
}

// Append list items
people.forEach(person => {
  let item = document.createElement('ul');

  item.innerHTML = `<a href="#" class="list-group-item">${person.name}<br><b>CODE: </b>${person.id}</a>`;
  item.addEventListener('click', onClick.bind(null, person));

  list.appendChild(item);
});

I'm wondering is it possible to loop trough php generated GeoJSON using this block of code

var lampe_hum_150n = L.geoJson(null, {
  pointToLayer: function (feature, latlng) {
    return L.marker(latlng, {
      icon: L.icon({
        iconUrl: "img/power_red.png",
        iconSize: [20, 28],
        iconAnchor: [12, 28],
        popupAnchor: [0, -25]
      }),
      title: feature.properties.sifra_lampe,
      riseOnHover: false,
      riseOffset: 100
    });
  },
  onEachFeature: function (feature, layer) {
    if (feature.properties) {

      var content = "<table class='table table-striped table-bordered table-condensed'>" + "<tr><th>Šifra trafostanice</th><td>" + feature.properties.ts_sifra + 
      "</td></tr>" + "<tr><th>Naziv trafostanice</th><td>" + feature.properties.ts_naziv + "</td></tr>" +  
      "<tr><th>Kod lampe</th><td>" + feature.properties.sifra_lampe + "</td></tr>" +
      "<tr><th>Tip/snaga lampe</th><td>" + feature.properties.tip_lampe + "</td></tr>" +
      "<tr><th>Vrsta stupa</th><td>" + feature.properties.vrsta_stupa + "</td></tr>" +
      "<tr><th>Adresa</th><td>" + feature.properties.adresa + "</td></tr>" +
      "<tr"+ (feature.properties.datum === 'Nema servisa' ? ' class="danger"' : '' || feature.properties.datum != 'Nema servisa' ? ' class="success"' : '') +"><th>Zadnji servis</th><td>" + feature.properties.datum + "</td></tr>" 
      "</table>";

      layer.on({
        click: function (e) {
          $("#feature-title").html(feature.properties.ts_sifra +'-'+ feature.properties.sifra_lampe+'<br>TS - '+feature.properties.ts_naziv);
          $("#feature-info").html(content);
          $("#featureModal").modal("show");
          highlight.clearLayers().addLayer(L.marker([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], {icon:ikonaClick_A}));
        }
      });
      $("#feature-list tbody").append('<tr class="feature-row" id="' + L.stamp(layer) + '" lat="' + layer.getLatLng().lat + '" lng="'
      + layer.getLatLng().lng + '"><td style="vertical-align: middle;"><img width="16" height="18" src="img/power_red.png"></td><td class="feature-name">'
      + layer.feature.properties.sifra_lampe + '</td><td style="vertical-align: middle;"><i class="fa fa-chevron-right pull-right"></i></td></tr>');
      rasvjetaSloj_150n.push({
        // pretražuje nam na topbaru po lokaciji
        // ako zamijenimo lokaciju i operator
        // onda će nam pretraživati po operatoru, a ne po lokaciji
        ts: layer.feature.properties.ts_sifra + '-',
        name: layer.feature.properties.sifra_lampe,
        tip: layer.feature.properties.tip_lampe,
        address: layer.feature.properties.adresa,
        source: "Lampe",
        id: L.stamp(layer),
        lat: layer.feature.geometry.coordinates[1],
        lng: layer.feature.geometry.coordinates[0]
      });
    }
  }
});
$.getJSON("php/rasvjeta_150n.php", function (data) {
  lampe_hum_150n.addData(data);
  map.addLayer(rasvjeta_sloj_150n);
});

instead of this:

let people = [
    {
      name: 'FIRST POINT',
      latLng: [46.210888, 15.647540],
      id: '2342fc7'
    },
    {
      name: 'SECOND POINT',
      latLng: [46.211888, 15.647540],
      id: 'djf3892'
    },
    {
      name: 'THIRD POINT',
      latLng: [46.2120888, 15.647540],
      id: '2837hf3'
    }
];

When I try to loop trough GeoJSON using this code

let people = $.getJSON("php/rasvjeta_150n.php", function (data) {
});

instead block from above, I get this error message

Uncaught TypeError: people.forEach is not a function

And here it is PHP code for generating GeoJSON from MySQL:

UPDATE II

With help of fellow ghybs I've manage to create some interaction between external items and map markers. But as I click on elements from external list it only zooms me on the same marker.I would like (if possible) when I click item on external list to zoom me on that same marker on the map.

Picture:

If I click on list with the code H12 it zooms me on the map marker with different code on the map. enter image description here

Here is the code:

function goTo(layer) {
    map.panTo(layer.getLatLng());
    layer.openPopup();
}

$.getJSON("php/rasvjeta_kvar.php", function(data) {
    geojson = L.geoJson(data, {
        pointToLayer: function(feature, latlng) {
            return L.marker(latlng, {
                icon: L.icon({
                    iconUrl: "img/power_red.png",
                    iconSize: [20, 28],
                    iconAnchor: [12, 28],
                    popupAnchor: [0, -25]
                }),
                title: feature.properties.sifra_lampe,
                riseOnHover: false,
                riseOffset: 100
            });
        },
        onEachFeature: function(feature, layer) {
            layer.bindPopup(feature.properties.tip_lampe +
                "<br>" + feature.properties.adresa + " u m<sup>2</sup>");

            $("#list").append('<a href="#" class="list-group-item">' + layer.feature.properties.sifra_lampe + ' - ' + layer.feature.properties.ts_sifra + '</a>');

            list.addEventListener("click", function() {
                goTo(layer);
            });
        }
    });
    geojson.addTo(map);
});
Community
  • 1
  • 1
Svinjica
  • 2,389
  • 2
  • 37
  • 66

2 Answers2

3

What you describe is a common use case. I am pretty sure there should be plenty resources (in particular on SO) that provide the same functionality.

As for the TypeError you report, note that jQuery's $.getJSON returns a jqXHR object, not an array.

As to implement your functionality, you already know that you can perform instructions for each GeoJSON feature through the onEachFeature option of L.geoJSON constructor. Therefore, why not simply building your list items in there, instead of trying to parse your people array separately? This is actually what your code seems to do, by appending a new row into #feature-list table.

The biggest advantage of this approach is that you can directly link your external item "click" event listener to the appropriate layer / marker, since it is available as parameter of the onEachFeature function:

function goTo(layer) {
    map.panTo(layer.getLatLng());
    layer.openPopup();
}

L.geoJSON(null, {
    onEachFeature: function (feature, layer) {
        // Whatever you want to add to your layer.

        // Build your external item.
        // Then attach the "click" event listener.
        item.addEventListener("click", function () {
            goTo(layer);
        });
    }
});
ghybs
  • 47,565
  • 6
  • 74
  • 99
  • @ghybs..Thank you for answer! I have a feeling that I'm one closer with your help! I'm just having a trouble now with interaction between external items and markers...I ll update answer with code for explaining purposes... I will accept answer – Svinjica Jan 21 '17 at 19:52
  • What is your `list`? It seems to me that you bind your event listener to the same element, therefore all listeners are executed, and the last one "wins". If you properly attach your listener to each item, it should work. Demo: http://playground-leaflet.rhcloud.com/like/1/edit?html,output – ghybs Jan 22 '17 at 02:31
  • BTW, if you want to avoid attaching many listeners (one per item), you can delegate to your container list, but you have to embed an id in your item (e.g. using dataset or jQuery's `.data()`), retrieve that id in the event listener, then retrieve the corresponding marker. By using jQuery's `data()`, I think you can also directly embed the marker, therefore you do not need to build a map of id to marker. – ghybs Jan 22 '17 at 02:36
1

One way of doing this is to bind a new popup to the same position on the map...

function openPopup(elementRightSide){
   L.popup() 
            .setLatLng(elementRightSide.lat, elementRightSide.lng])
            .setContent(elementRightSide.content)
            .openOn(map);
}
rm -rf .
  • 473
  • 1
  • 4
  • 14