JamalDols
JamalDols

Reputation: 510

Chart.js inside popup on leaflet?

Maybe this is a silly question but I am unable to include a chart for each point on a map.

I am collecting the data from a JSON, this data I print it in the popup, each one with its class .scoreA, .scoreB... I would like from this data to create a chart for each point like the one I have. I would prefer to take them from the content of the popup (.scoreA, .scoreB) rather than from the JSON in case the structure changes. is it possible?

var mymap = L.map('mapid').setView([39.46975, -0.37739], 8 );
L.tileLayer('https://api.mapbox.com/styles/v1/jamaldols/cktwljkom0vzo18l9ggtnky83/tiles/256/{z}/{x}/{y}@2x?access_token={accessToken}', {
    attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
    maxZoom: 12,
    minZoom: 8,
    id: 'mapbox/standard',
    tileSize: 512,
    zoomOffset: -1,
    // maxNativeZoom: 16,
    accessToken: ''
}).addTo(mymap);






$.getJSON('data.geo.json', function (geojson) {
  L.geoJson(geojson, {
    pointToLayer: function (feature, latlng) {
      return L.marker(latlng);
    },
    onEachFeature: function (feature, layer) {



      const coordinates = feature.geometry.coordinates;
      const normalizedCoordinates = feature.geometry.coordinates.sort(function(a,b){return a.typeid-b.typeid});
      
      console.log( `Coordinates:     ${coordinates}`);
      console.log( `Coordinates N:   ${normalizedCoordinates}`);
      

      const content = 
      `
      <p id="heading">${feature.properties.name}</p>
      <p class="scoreA"><strong>ScoreA: </strong>${feature.properties.scoreA}</p>
      <p class="scoreB"><strong>ScoreB: </strong>${feature.properties.scoreB}</p>
      <p class="scoreC"><strong>ScoreC: </strong>${feature.properties.scoreC}</p>
      <p class="scoreD"><strong>ScoreD: </strong>${feature.properties.scoreD}</p>

      <div class="popup__chart">chart</div>
      `;
      layer.on('click', function (e) {
        
        document.getElementById("popup__content").innerHTML = content;
        $(".popup").fadeOut(10);
        $(".popup").fadeIn("slow");
        
      
        console.log( `Click on ${feature.properties.name}`);
        const maxZoom = mymap.getMaxZoom();
        console.log(maxZoom)
        mymap.flyTo(this.getLatLng(), maxZoom, {easeLinearity: 0.12, duration:1});
      });


    }
  }).addTo(mymap);
});

//Chart

  var marksCanvas = document.getElementById("marksChart");
  var marksData = {
    labels: ["Score A", "Score B", "Score C", "Score D"],
    datasets: [{
      label: "City",
      backgroundColor: "rgba(200,0,0,1)",
      data: [65, 60, 90, 80]
    },]
  };
  var radarChart = new Chart(marksCanvas, {
    type: 'radar',
    data: marksData
  });



$(document).ready(function(){


  $(".popup__bar__close").click(function(){
    $('.popup').css('display', 'none');
    mymap.flyTo([39.46975, -0.37739], 8, {easeLinearity: 0.12, duration:1});
  });

});
html,
body {
height: 100%;
font-family: 'Montserrat', sans-serif;
}


.popup-fixed {
position: fixed;
top: auto;
bottom: 0 !important;
left: 0 !important;
right: 0 !important;
transform: none !important;
margin: 0;
border-radius: 0;

}
.leaflet-popup-tip-container {
display: none;
}

.leaflet-popup-content-wrapper {
border-radius: 0;
}

.popup {
  width: 300px;
  padding-bottom: 50px;
  background: white;
  position: absolute;
  top: 50px;
  right: 50px;
  border: none;
  display:none;
  z-index: 1000;
}
#heading {
  
  
  font-size: 35px;
  color:black;
  text-transform: uppercase;
  margin: 15px 0;
}
#main { 
  display: flex;
  overflow: hidden;

}
.popup {

}
.popup__bar {
  width: 100%;
  height: 50px;
  position: relative;
  display: flex;
  align-items: center;
  background: black;

}
.popup__bar__close {
  background-image: url(img/close.svg);
  background-size: 30px;
  background-repeat: no-repeat;
  background-position: center;
  position: absolute;
  height: 30px;
  width: 30px;
  right: 15px;
  transform: rotate(45deg);
  cursor: pointer;

}

.popup__chart {
}
.popup__chart img{
  max-width: 100%;
  height: auto;
}

#popup__content {
  padding: 0 30px; 
}
#info {

}


#footer {
  font-family: 'Roboto Condensed', sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  text-transform: uppercase;
  letter-spacing: 6px;
  height: 70px;
  position: absolute;
  background: white;
  bottom: 0;
  width: calc(100% - 90px);
  right: 0;

}


#marksChart {
  display: block;
  box-sizing: border-box;
  height: 250px;
  width: 250px;
  position: absolute;
  top: 100px;
  left: 90px;
  background: white;
  z-index: 200000;
  border-radius: 12px;
  padding: 20px;
}
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js" integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <style>
    #mapid { 
      height: calc(100vh - 70px);
      width: calc(100vw - 90px);
     }
    body {
      padding: 0;
      margin: 0;
    }
  
  </style>
<main id="main">
  
  <div id="mapid"></div>
  
</main>
<div class="chart-container" style="max-width: 200px;">
  <canvas id="marksChart" width="200" height="400"></canvas>
</div>
<script>



</script>


 
  <div class="popup"> 
    <div class="popup__bar">
      <div class="popup__bar__close"></div>
    </div>
    
    <div id="popup__content"></div>
  </div>
  

  <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
  <script src="https://unpkg.com/[email protected]/dist/leaflet.js"
  integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
  crossorigin=""></script>
  <!-- <script type="text/javascript" src="data.geo.json"></script> -->
  
  <script type="text/javascript" src="main.js"></script>
  
  
</body>

Upvotes: 3

Views: 1536

Answers (1)

Falke Design
Falke Design

Reputation: 11338

Change your javascript to following:

$.getJSON('data.geo.json', function (geojson) {
  L.geoJson(geojson, {
    pointToLayer: function (feature, latlng) {
      return L.marker(latlng);
    },
    onEachFeature: function (feature, layer) {
      const coordinates = feature.geometry.coordinates;
      const normalizedCoordinates = feature.geometry.coordinates.sort(function(a,b){return a.typeid-b.typeid});

      console.log( `Coordinates:     ${coordinates}`);
      console.log( `Coordinates N:   ${normalizedCoordinates}`);

      const content =
      `
      <p id="heading">${feature.properties.name}</p>
      <p class="scoreA"><strong>ScoreA: </strong><span>${feature.properties.scoreA}</span></p>
      <p class="scoreB"><strong>ScoreB: </strong><span>${feature.properties.scoreB}</span></p>
      <p class="scoreC"><strong>ScoreC: </strong><span>${feature.properties.scoreC}</span></p>
      <p class="scoreD"><strong>ScoreD: </strong><span>${feature.properties.scoreD}</span></p>

      <div class="popup__chart">chart</div>
      `;
      layer.on('click', function (e) {

        var popupElm = document.getElementById("popup__content");
        popupElm.innerHTML = content;
        $(".popup").fadeOut(10);
        $(".popup").fadeIn("slow");

        console.log( `Click on ${feature.properties.name}`);
        const maxZoom = mymap.getMaxZoom();
        console.log(maxZoom)
        mymap.flyTo(this.getLatLng(), maxZoom, {easeLinearity: 0.12, duration:1});


        var marksData = {
          labels: ["Score A", "Score B", "Score C", "Score D"],
          datasets: [{
            label: "City",
            backgroundColor: "rgba(200,0,0,1)",
            data: [
              popupElm.querySelectorAll('.scoreA span')[0].innerHTML,
              popupElm.querySelectorAll('.scoreB span')[0].innerHTML,
              popupElm.querySelectorAll('.scoreC span')[0].innerHTML,
              popupElm.querySelectorAll('.scoreD span')[0].innerHTML
              ],
          },]
        };
        if(radarChart){
          radarChart.destroy();
        }
        radarChart = new Chart(marksCanvas, {
          type: 'radar',
          data: marksData
        });
      });


    }
  }).addTo(mymap);
});

//Chart
var marksCanvas = document.getElementById("marksChart");
var radarChart = null;


$(document).ready(function(){
  $(".popup__bar__close").click(function(){
    $('.popup').css('display', 'none');
    mymap.flyTo([39.46975, -0.37739], 8, {easeLinearity: 0.12, duration:1});
  });
});

What changed:

  1. Add in the Popup around the score value a span, so it can easily read out

    <p class="scoreA"><strong>ScoreA: </strong><span>${feature.properties.scoreA}</span></p>

  2. Move the chart generation into the click function but keep the global variables

  3. Destroy the existing chart, else an error is thrown radarChart.destroy();

  4. Get the valus from popup and use it in the data array. It searches for the class .scoreA and then it get the child span element

    popupElm.querySelectorAll('.scoreA span')[0].innerHTML,


Btw. you can also get the values from the clicked layer:

data: [
              layer.feature.properties.scoreA,
              layer.feature.properties.scoreB,
              layer.feature.properties.scoreC,
              layer.feature.properties.scoreD,
            ]

Upvotes: 2

Related Questions