Project

General

Profile

create HTML div for Leaflet map

Added by Pedro Vicente over 7 years ago

I'm trying to generate a Leaflet map, similar to WGoogleMap

The Leaflet API requires an HTML

to be rendered, so how I accomplish that, to generate a div dynamically, or load

an existing HTML too, don't know if possible?

the WT API has functions for

DomElement createElement

but it does not have many Javascript/HTML examples of how to use

basically I want to create this HTML page

<!DOCTYPE html>
<html>
<head>
<title>Map</title>
<link rel="stylesheet" href="leaflet.css" />
<script src="leaflet.js"></script>
<style>
#map { height: 100%;}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var layer_base = L.tileLayer(
'http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{
maxZoom: 20,
subdomains:['mt0','mt1','mt2','mt3']
}
);


var map = new L.Map('map', {
center: new L.LatLng(38.9072, -77.0369),
zoom: 8,
layers: [layer_base]
});
</script>
</body>
</html>

so I came out with

namespace Wt
{
  LOGGER("WLeaflet");

  ///////////////////////////////////////////////////////////////////////////////////////
  //WLeaflet::WLeaflet
  ///////////////////////////////////////////////////////////////////////////////////////

  WLeaflet::WLeaflet(WContainerWidget *parent)
  {
    setImplementation(new WContainerWidget());
    if (parent)
    {
      parent->addWidget(this);
    }
    this->addCssRule("#map_id" + id(), "position:absolute; top:0; bottom:0; width:100%;");
    Wt::WApplication * app = Wt::WApplication::instance();
    app->useStyleSheet(Wt::WCssStyleSheet(Wt::WLink("https://unpkg.com/leaflet@1.0.3/dist/leaflet.css")));
    const std::string mburi = "https://unpkg.com/leaflet@1.0.3/dist/leaflet.js";
    app->require(mburi, "leaflet");
  }

  ///////////////////////////////////////////////////////////////////////////////////////
  //WLeaflet::~WLeaflet
  ///////////////////////////////////////////////////////////////////////////////////////

  WLeaflet::~WLeaflet()
  {

  }

  ///////////////////////////////////////////////////////////////////////////////////////
  //WLeaflet::render
  ///////////////////////////////////////////////////////////////////////////////////////

  void WLeaflet::render(WFlags<RenderFlag> flags)
  {
    if (flags & Wt::RenderFull)
    {
      Wt::WApplication * app = Wt::WApplication::instance();
      Wt::WString initFunction = app->javaScriptClass() + ".init_mapbox_" + id();

      Wt::WStringStream stream;

      stream
        << "{ " << initFunction.toUTF8() << " = function() {\n"
        << "  var self = " << jsRef() << ";\n"
        << "  if (!self) {\n"
        << "    setTimeout(" << initFunction.toUTF8() << ", 0);\n"
        << "  }\n";

      stream
        << "  var layer_base = L.tileLayer(\n"
        << "  'http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{\n"
        << "  maxZoom: 20,\n"
        << "  subdomains:['mt0','mt1','mt2','mt3']\n"
        << "  }\n"
        << "  );\n";

      stream
        << "  var map = new L.Map('map_id', {\n"
        << "  center: new L.LatLng(38.9072, -77.0369),\n"
        << "  zoom: 8,\n"
        << "  layers: [layer_base]\n"
        << "  });\n";

      stream
        << "  setTimeout(function(){ delete " << initFunction.toUTF8() << ";}, 0)};\n"
        << "}\n"
        << initFunction.toUTF8() << "();\n";

      LOG_INFO(stream.str());
      app->doJavaScript(stream.str());
    }

    Wt::WCompositeWidget::render(flags);
  }
}

but the Leaflet API gives an error on the browser saying

Error: Map container not found.

which I think is because of the missing div

so , how can the div be done ?


Replies (2)

RE: create HTML div for Leaflet map - Added by Pedro Vicente over 7 years ago

I got the leaflet map displayed by setting the

to the "self" variable as done in WGoogleMap

stream
        << "  var map = new L.Map(self, {\n"

however the map is displayed with a very small height as seen in the attached file

It seems Leaflet requires this CSS

html, body {
   height: 100%;
}

as explained here

https://stackoverflow.com/questions/16543446/how-to-make-leaflet-map-height-variable

how can this be done with WT ?

the complete code

#include "Wt/WLogger"
#include <Wt/WLeaflet.hh>
#include <Wt/WApplication>
#include <Wt/WContainerWidget>
#include "web/WebUtils.h"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <utility>
#include <iostream>
#include <cmath>

namespace Wt
{
  LOGGER("WLeaflet");

  ///////////////////////////////////////////////////////////////////////////////////////
  //WLeaflet::WLeaflet
  ///////////////////////////////////////////////////////////////////////////////////////

  WLeaflet::WLeaflet(WContainerWidget *parent)
  {
    setImplementation(new WContainerWidget());
    if (parent)
    {
      parent->addWidget(this);
    }

    this->addCssRule("#" + id(), "position:absolute; top:0; bottom:0; right: 0; left: 0; width: 100%; height: 100%");
    Wt::WApplication * app = Wt::WApplication::instance();
    app->useStyleSheet(Wt::WCssStyleSheet(Wt::WLink("https://unpkg.com/leaflet@1.0.3/dist/leaflet.css")));
    const std::string mburi = "https://unpkg.com/leaflet@1.0.3/dist/leaflet.js";
    app->require(mburi, "leaflet");
  }

  ///////////////////////////////////////////////////////////////////////////////////////
  //WLeaflet::~WLeaflet
  ///////////////////////////////////////////////////////////////////////////////////////

  WLeaflet::~WLeaflet()
  {

  }

  ///////////////////////////////////////////////////////////////////////////////////////
  //WLeaflet::render
  ///////////////////////////////////////////////////////////////////////////////////////

  void WLeaflet::render(WFlags<RenderFlag> flags)
  {
    if (flags & Wt::RenderFull)
    {
      Wt::WApplication * app = Wt::WApplication::instance();
      Wt::WString initFunction = app->javaScriptClass() + ".init_leaflet_" + id();

      Wt::WStringStream stream;

      stream
        << "{ " << initFunction.toUTF8() << " = function() {\n"
        << "  var self = " << jsRef() << ";\n"
        << "  if (!self) {\n"
        << "    setTimeout(" << initFunction.toUTF8() << ", 0);\n"
        << "  }\n";

      stream
        << "  var layer_base = L.tileLayer(\n"
        << "  'http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',{\n"
        << "  maxZoom: 20,\n"
        << "  subdomains:['mt0','mt1','mt2','mt3']\n"
        << "  }\n"
        << "  );\n";

      stream
        << "  var map = new L.Map(self, {\n"
        << "  center: new L.LatLng(38.9072, -77.0369),\n"
        << "  zoom: 8,\n"
        << "  layers: [layer_base]\n"
        << "  });\n";

      stream
        << "  setTimeout(function(){ delete " << initFunction.toUTF8() << ";}, 0)};\n"
        << "}\n"
        << initFunction.toUTF8() << "();\n";

      LOG_INFO(stream.str());
      app->doJavaScript(stream.str());
    }

    Wt::WCompositeWidget::render(flags);
  }
}

RE: create HTML div for Leaflet map - Added by Pedro Vicente over 7 years ago

after a bit of research (read: intuitive guess) adding CSS to HTML can be done with

this->addCssRule("html", "height: 100%;");
this->addCssRule("body", "height: 100%;");

for

html, body {
   height: 100%;
}
    (1-2/2)