Using a newer version of Leaflet (v1.9 vs v1.3) for the ability to use canvas

Feature(s) impacted

Leaflet maps in Smart views

Observed behavior

When attempting to import Leaflet 1.9, to allow for drawing on a canvas, canvas rendering of e.g. polygons and other stuff doesn’t work. I assume this is because Leaflet 1.3 is bundled (window.L is available on all Forest pages), and there could be something edgy going on, when two versions are loaded simultaneous. Have verified that the exact same JS draws perfectly outside of Forest on a canvas, but not within the context of the Forest DOM.

Expected behavior

I’d be able to draw on a canvas with Leaflet in a Smart view with Leaflet 1.9, loaded as an external script.

Failure Logs

No logs

Context

  • Project name: Monta
  • Environment name: All

Hi @nicklasmonta and welcome to the community :slight_smile:

I was able to load polygons on my hand.
Do you load simultaneous versions of leaflet for the same smart view ?
Loading it through the function loadExternalJavascript should do the job.
Example :

import { loadExternalJavascript } from 'client/utils/smart-view-utils';

await loadExternalJavascript('//cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.1/leaflet.js');

If it does not resolve your case, could you please send me here or by private message the code of your smart view ?

Best regards,

Shohan

Thank you.

Do you attempt to instantiate the map with preferCanvas: true as well? That’s the issue I’m hammering my head against.

Attempted to do a minimal repro, which also causes the issue on my end, and if you change preferCanvas to false, it renders fine:

Component:

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import { action } from '@ember/object';
import { observes } from '@ember-decorators/object';
import { tracked } from '@glimmer/tracking';
import { guidFor } from '@ember/object/internals';
import { triggerSmartAction, deleteRecords, getCollectionId, loadExternalStyle, loadExternalJavascript } from 'client/utils/smart-view-utils';


export default class extends Component {
  @service router;
  @service store;

  @tracked map = null;
  @tracked loaded = false;

  constructor(...args) {
    super(...args);

    this.loadPlugin();
  }
  
  get mapId() {
    return `map-${guidFor(this)}`;
  }

  async loadPlugin() {
    if (this.loaded) {
      return
    }
    
    await loadExternalStyle('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.3/leaflet.css');
    
    await loadExternalJavascript('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.3/leaflet.js');
    
    this.loaded = true;
    this.displayMap();
  }


  @action
  displayMap(lat = 48.8566, lng = 2.3522, zoom = 2, addMode = false, polyColor = 'yellow') {
    if (this.map) {
      this.map.off();
      this.map.remove();
      this.map = null;
    }

    this.map = new L.Map(this.mapId, { preferCanvas: true });
    this.map.doubleClickZoom.disable();

    let mapEq = this.map;

    const osmUrl = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png';
    const osmAttrib = '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions">CartoDB</a>';
    const osm = new L.TileLayer(osmUrl, { attribution: osmAttrib });

    this.map.setView(new L.LatLng(lat, lng), zoom);
    this.map.addLayer(osm);

    let markers = [];
    let marker = [];
    let coordinates = null;
    let coordinatesArray = null;

    let self = this;
    
    const coordinatesList = [[[{"x":11.980590820312,"y":54.575245800783},{"x":11.958618164062,"y":54.6801830971},{"x":12.01904296875,"y":54.724620194924},{"x":12.052001953125,"y":54.762670400255},{"x":12.15087890625,"y":54.822843475681},{"x":12.12890625,"y":54.860801391642},{"x":12.139892578125,"y":54.889246403076},{"x":12.28271484375,"y":54.908198592989},{"x":12.299194335937,"y":54.942921113078},{"x":12.392578125,"y":54.955540054617},{"x":12.5244140625,"y":54.946076219874},{"x":12.551879882812,"y":54.974461039595},{"x":12.50244140625,"y":55.002825809793},{"x":12.403564453125,"y":55.01857535474},{"x":12.3046875,"y":55.028022112993},{"x":12.28271484375,"y":55.059495230496},{"x":12.189331054688,"y":55.081511700352},{"x":12.178344726562,"y":55.109800793144},{"x":12.145385742188,"y":55.138069871015},{"x":12.112426757812,"y":55.160043098769},{"x":12.117919921875,"y":55.188276612555},{"x":12.145385742188,"y":55.21649013169},{"x":12.277221679688,"y":55.257207708312},{"x":12.376098632812,"y":55.241552035652},{"x":12.420043945312,"y":55.257207708312},{"x":12.442016601562,"y":55.282243960527},{"x":12.45849609375,"y":55.307264433832},{"x":12.453002929688,"y":55.354135310211},{"x":12.37060546875,"y":55.404069827006},{"x":12.299194335937,"y":55.39783145936},{"x":12.249755859375,"y":55.419661438675},{"x":12.183837890625,"y":55.466399363938},{"x":12.211303710938,"y":55.509971499832},{"x":12.2607421875,"y":55.556602469867},{"x":12.315673828125,"y":55.572133842414},{"x":12.398071289062,"y":55.606281251302},{"x":12.513427734375,"y":55.621792980631},{"x":12.551879882812,"y":55.575239380091},{"x":12.573852539062,"y":55.559709235632},{"x":12.667236328125,"y":55.575239380091},{"x":12.755126953125,"y":55.572133842414},{"x":12.815551757812,"y":55.62489459016},{"x":12.81005859375,"y":55.646598985637},{"x":12.793579101562,"y":55.668291359004},{"x":12.7001953125,"y":55.65279803319},{"x":12.606811523438,"y":55.696163893909},{"x":12.606811523438,"y":55.727110085046},{"x":12.595825195312,"y":55.76112258902},{"x":12.59033203125,"y":55.853733350714},{"x":12.513427734375,"y":55.92766341247},{"x":12.595825195312,"y":56.022948079627},{"x":12.606811523438,"y":56.050567423205},{"x":12.48046875,"y":56.087362474951},{"x":12.387084960938,"y":56.111873000398},{"x":12.28271484375,"y":56.117998193908},{"x":12.19482421875,"y":56.102683381877},{"x":12.035522460938,"y":56.035225783699},{"x":11.876220703125,"y":55.970724262317},{"x":11.876220703125,"y":55.955350884537},{"x":11.88720703125,"y":55.906115026012},{"x":11.9091796875,"y":55.853733350714},{"x":11.925659179688,"y":55.829058688584},{"x":11.870727539062,"y":55.810542413402},{"x":11.77734375,"y":55.795105452237},{"x":11.7333984375,"y":55.841397977195},{"x":11.700439453125,"y":55.88763544617},{"x":11.75537109375,"y":55.918429856308},{"x":11.77734375,"y":55.955350884537},{"x":11.749877929688,"y":55.989164255468},{"x":11.716918945312,"y":55.976871903595},{"x":11.6455078125,"y":55.952275476109},{"x":11.585083007812,"y":55.967650075307},{"x":11.508178710938,"y":55.970724262317},{"x":11.420288085938,"y":55.98301856795},{"x":11.321411132812,"y":55.989164255468},{"x":11.27197265625,"y":55.99838095536},{"x":11.348876953125,"y":55.9461239263},{"x":11.370849609375,"y":55.939971399147},{"x":11.42578125,"y":55.9461239263},{"x":11.480712890625,"y":55.915351515407},{"x":11.502685546875,"y":55.88763544617},{"x":11.497192382812,"y":55.862982311976},{"x":11.392822265625,"y":55.853733350714},{"x":11.332397460937,"y":55.819801652442},{"x":11.244506835938,"y":55.773483422605},{"x":11.178588867188,"y":55.76112258902},{"x":11.002807617188,"y":55.724016568961},{"x":10.931396484375,"y":55.745666035248},{"x":10.87646484375,"y":55.733296381987},{"x":10.903930664062,"y":55.683778552901},{"x":11.063232421875,"y":55.596971267985},{"x":11.167602539062,"y":55.537956716302},{"x":11.090698242187,"y":55.537956716302},{"x":11.112670898438,"y":55.500638670267},{"x":11.162109375,"y":55.453941329433},{"x":11.162109375,"y":55.400950766263},{"x":11.123657226562,"y":55.332269133402},{"x":11.112670898438,"y":55.301010794496},{"x":11.14013671875,"y":55.260338102925},{"x":11.145629882812,"y":55.229023057406},{"x":11.134643554687,"y":55.191412435271},{"x":11.2060546875,"y":55.131789583022},{"x":11.222534179688,"y":55.16945649211},{"x":11.288452148438,"y":55.175730853116},{"x":11.414794921875,"y":55.16945649211},{"x":11.530151367188,"y":55.147488450471},{"x":11.656494140625,"y":55.138069871015},{"x":11.738891601562,"y":55.084655921502},{"x":11.75537109375,"y":55.028022112993},{"x":11.848754882812,"y":55.00912637001},{"x":11.898193359375,"y":54.971308160969},{"x":11.804809570312,"y":54.958694171017},{"x":11.678466796875,"y":54.936610156606},{"x":11.766357421875,"y":54.876606654109},{"x":11.596069335938,"y":54.914514007665},{"x":11.585083007812,"y":54.882927024214},{"x":11.596069335938,"y":54.961848039842},{"x":11.585083007812,"y":54.999675158536},{"x":11.453247070312,"y":54.987070078949},{"x":11.343383789062,"y":54.983918190363},{"x":11.167602539062,"y":54.980766054282},{"x":10.997314453125,"y":54.936610156606},{"x":10.975341796875,"y":54.854477551567},{"x":10.975341796875,"y":54.797518359659},{"x":11.013793945312,"y":54.734136097639},{"x":11.282958984375,"y":54.696059077583},{"x":11.326904296875,"y":54.651590680027},{"x":11.409301757812,"y":54.61661705439},{"x":11.464233398438,"y":54.61661705439},{"x":11.568603515625,"y":54.6325178856},{"x":11.661987304688,"y":54.661123722066},{"x":11.749877929688,"y":54.638876477958},{"x":11.832275390625,"y":54.626158298923},{"x":11.848754882812,"y":54.667477840946},{"x":11.892700195312,"y":54.6325178856},{"x":11.892700195312,"y":54.584796743679},{"x":11.936645507812,"y":54.556137198405},{"x":11.980590820312,"y":54.575245800783}]]];
  
    coordinatesList.forEach(function (coordinates, i) {
      coordinatesArray = coordinates[0];
      markers = [];
      coordinatesArray.forEach(function(coordinate, j) {
        marker = [];
        marker.push(coordinate.y);
        marker.push(coordinate.x);
        markers.push(marker);
        let marker = L.marker(marker);
      });

      L.polygon(markers , {color: polyColor}).addTo(mapEq);
    });
  }
}

Template:

<div id={{this.mapId}} class="c-map1" {{did-insert this.displayMap}}></div>

Style:

.c-map1 {
  width: 100%;
  height: 100%;
}

Seems my comment disappeared :frowning:

Thanks!

Do you instantiate the map with preferCanvas: true? That’s the issue I’m hammering my head against.

Did a small repro, with works fine with preferCanvas: false, but not true. It works fine outside of Forest.

Components:

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import { action } from '@ember/object';
import { observes } from '@ember-decorators/object';
import { tracked } from '@glimmer/tracking';
import { guidFor } from '@ember/object/internals';
import { triggerSmartAction, deleteRecords, getCollectionId, loadExternalStyle, loadExternalJavascript } from 'client/utils/smart-view-utils';


export default class extends Component {
  @service router;
  @service store;

  @tracked map = null;
  @tracked loaded = false;

  constructor(...args) {
    super(...args);

    this.loadPlugin();
  }
  
  get mapId() {
    return `map-${guidFor(this)}`;
  }

  async loadPlugin() {
    if (this.loaded) {
      return
    }
    
    await loadExternalStyle('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.3/leaflet.css');
    
    await loadExternalJavascript('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.3/leaflet.js');
    
    this.loaded = true;
    this.displayMap();
  }


  @action
  displayMap(lat = 48.8566, lng = 2.3522, zoom = 2, addMode = false, polyColor = 'yellow') {
    if (this.map) {
      this.map.off();
      this.map.remove();
      this.map = null;
    }

    this.map = new L.Map(this.mapId, { preferCanvas: false });
    this.map.doubleClickZoom.disable();

    let mapEq = this.map;

    const osmUrl = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png';
    const osmAttrib = '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions">CartoDB</a>';
    const osm = new L.TileLayer(osmUrl, { attribution: osmAttrib });

    this.map.setView(new L.LatLng(lat, lng), zoom);
    this.map.addLayer(osm);

    let markers = [];
    let marker = [];
    let coordinates = null;
    let coordinatesArray = null;

    let self = this;
    
    const coordinatesList = [[[{"x":11.980590820312,"y":54.575245800783},{"x":11.958618164062,"y":54.6801830971},{"x":12.01904296875,"y":54.724620194924},{"x":12.052001953125,"y":54.762670400255},{"x":12.15087890625,"y":54.822843475681},{"x":12.12890625,"y":54.860801391642},{"x":12.139892578125,"y":54.889246403076},{"x":12.28271484375,"y":54.908198592989},{"x":12.299194335937,"y":54.942921113078},{"x":12.392578125,"y":54.955540054617},{"x":12.5244140625,"y":54.946076219874},{"x":12.551879882812,"y":54.974461039595},{"x":12.50244140625,"y":55.002825809793},{"x":12.403564453125,"y":55.01857535474},{"x":12.3046875,"y":55.028022112993},{"x":12.28271484375,"y":55.059495230496},{"x":12.189331054688,"y":55.081511700352},{"x":12.178344726562,"y":55.109800793144},{"x":12.145385742188,"y":55.138069871015},{"x":12.112426757812,"y":55.160043098769},{"x":12.117919921875,"y":55.188276612555},{"x":12.145385742188,"y":55.21649013169},{"x":12.277221679688,"y":55.257207708312},{"x":12.376098632812,"y":55.241552035652},{"x":12.420043945312,"y":55.257207708312},{"x":12.442016601562,"y":55.282243960527},{"x":12.45849609375,"y":55.307264433832},{"x":12.453002929688,"y":55.354135310211},{"x":12.37060546875,"y":55.404069827006},{"x":12.299194335937,"y":55.39783145936},{"x":12.249755859375,"y":55.419661438675},{"x":12.183837890625,"y":55.466399363938},{"x":12.211303710938,"y":55.509971499832},{"x":12.2607421875,"y":55.556602469867},{"x":12.315673828125,"y":55.572133842414},{"x":12.398071289062,"y":55.606281251302},{"x":12.513427734375,"y":55.621792980631},{"x":12.551879882812,"y":55.575239380091},{"x":12.573852539062,"y":55.559709235632},{"x":12.667236328125,"y":55.575239380091},{"x":12.755126953125,"y":55.572133842414},{"x":12.815551757812,"y":55.62489459016},{"x":12.81005859375,"y":55.646598985637},{"x":12.793579101562,"y":55.668291359004},{"x":12.7001953125,"y":55.65279803319},{"x":12.606811523438,"y":55.696163893909},{"x":12.606811523438,"y":55.727110085046},{"x":12.595825195312,"y":55.76112258902},{"x":12.59033203125,"y":55.853733350714},{"x":12.513427734375,"y":55.92766341247},{"x":12.595825195312,"y":56.022948079627},{"x":12.606811523438,"y":56.050567423205},{"x":12.48046875,"y":56.087362474951},{"x":12.387084960938,"y":56.111873000398},{"x":12.28271484375,"y":56.117998193908},{"x":12.19482421875,"y":56.102683381877},{"x":12.035522460938,"y":56.035225783699},{"x":11.876220703125,"y":55.970724262317},{"x":11.876220703125,"y":55.955350884537},{"x":11.88720703125,"y":55.906115026012},{"x":11.9091796875,"y":55.853733350714},{"x":11.925659179688,"y":55.829058688584},{"x":11.870727539062,"y":55.810542413402},{"x":11.77734375,"y":55.795105452237},{"x":11.7333984375,"y":55.841397977195},{"x":11.700439453125,"y":55.88763544617},{"x":11.75537109375,"y":55.918429856308},{"x":11.77734375,"y":55.955350884537},{"x":11.749877929688,"y":55.989164255468},{"x":11.716918945312,"y":55.976871903595},{"x":11.6455078125,"y":55.952275476109},{"x":11.585083007812,"y":55.967650075307},{"x":11.508178710938,"y":55.970724262317},{"x":11.420288085938,"y":55.98301856795},{"x":11.321411132812,"y":55.989164255468},{"x":11.27197265625,"y":55.99838095536},{"x":11.348876953125,"y":55.9461239263},{"x":11.370849609375,"y":55.939971399147},{"x":11.42578125,"y":55.9461239263},{"x":11.480712890625,"y":55.915351515407},{"x":11.502685546875,"y":55.88763544617},{"x":11.497192382812,"y":55.862982311976},{"x":11.392822265625,"y":55.853733350714},{"x":11.332397460937,"y":55.819801652442},{"x":11.244506835938,"y":55.773483422605},{"x":11.178588867188,"y":55.76112258902},{"x":11.002807617188,"y":55.724016568961},{"x":10.931396484375,"y":55.745666035248},{"x":10.87646484375,"y":55.733296381987},{"x":10.903930664062,"y":55.683778552901},{"x":11.063232421875,"y":55.596971267985},{"x":11.167602539062,"y":55.537956716302},{"x":11.090698242187,"y":55.537956716302},{"x":11.112670898438,"y":55.500638670267},{"x":11.162109375,"y":55.453941329433},{"x":11.162109375,"y":55.400950766263},{"x":11.123657226562,"y":55.332269133402},{"x":11.112670898438,"y":55.301010794496},{"x":11.14013671875,"y":55.260338102925},{"x":11.145629882812,"y":55.229023057406},{"x":11.134643554687,"y":55.191412435271},{"x":11.2060546875,"y":55.131789583022},{"x":11.222534179688,"y":55.16945649211},{"x":11.288452148438,"y":55.175730853116},{"x":11.414794921875,"y":55.16945649211},{"x":11.530151367188,"y":55.147488450471},{"x":11.656494140625,"y":55.138069871015},{"x":11.738891601562,"y":55.084655921502},{"x":11.75537109375,"y":55.028022112993},{"x":11.848754882812,"y":55.00912637001},{"x":11.898193359375,"y":54.971308160969},{"x":11.804809570312,"y":54.958694171017},{"x":11.678466796875,"y":54.936610156606},{"x":11.766357421875,"y":54.876606654109},{"x":11.596069335938,"y":54.914514007665},{"x":11.585083007812,"y":54.882927024214},{"x":11.596069335938,"y":54.961848039842},{"x":11.585083007812,"y":54.999675158536},{"x":11.453247070312,"y":54.987070078949},{"x":11.343383789062,"y":54.983918190363},{"x":11.167602539062,"y":54.980766054282},{"x":10.997314453125,"y":54.936610156606},{"x":10.975341796875,"y":54.854477551567},{"x":10.975341796875,"y":54.797518359659},{"x":11.013793945312,"y":54.734136097639},{"x":11.282958984375,"y":54.696059077583},{"x":11.326904296875,"y":54.651590680027},{"x":11.409301757812,"y":54.61661705439},{"x":11.464233398438,"y":54.61661705439},{"x":11.568603515625,"y":54.6325178856},{"x":11.661987304688,"y":54.661123722066},{"x":11.749877929688,"y":54.638876477958},{"x":11.832275390625,"y":54.626158298923},{"x":11.848754882812,"y":54.667477840946},{"x":11.892700195312,"y":54.6325178856},{"x":11.892700195312,"y":54.584796743679},{"x":11.936645507812,"y":54.556137198405},{"x":11.980590820312,"y":54.575245800783}]]];
  
    coordinatesList.forEach(function (coordinates, i) {
      coordinatesArray = coordinates[0];
      markers = [];
      coordinatesArray.forEach(function(coordinate, j) {
        marker = [];
        marker.push(coordinate.y);
        marker.push(coordinate.x);
        markers.push(marker);
        let marker = L.marker(marker);
      });

      L.polygon(markers , {color: polyColor}).addTo(mapEq);
    });
  }
}

Template:

<div id={{this.mapId}} class="c-map1" {{did-insert this.displayMap}}></div>

Style:

.c-map1 {
  width: 100%;
  height: 100%;
}

Hi,

I printed the leaflet version and I had 1.9.3, so I am not sure that the version has to do with it.
I am not sure how I can help you on this subject.

In addition to that, I am not sure if it is related, but with with your snippet of code I had a console log error. It might not be linked to your issue, but it is a beginning where I would look into.

Kind regards,

Shohan

Hi again,

I trimmed it down, and spent some more time debugging. So a couple of things I’ve found out, in case anyone else stumbles upon this:

  • It’s not related to the version. It should work fine in 1.3.1 as well. Forestadmin bundles 1.3.1, but that should be fine.
  • The canvas looks like it doesn’t render, but this can be disproved by selecting the canvas element, and getting it’s blob or dataURL; in my case it definitely is drawn to the canvas (e.g. document.querySelector('#leaflet canvas').toDataURL().
  • The canvas element visually has a height of 0 and a width of 0 (document.querySelector('#leaflet canvas').clientWidth or clientHeight), although width and `height has correct values.

This simply boils it down to ensuring that the clientWidth and clientHeight gets properly set. It may just be the display rules of parent elements that are triggering this behavior.

Not entirely sure about this, but I’d assume it can be a problem with other canvas elements in Smart Views in Forest as well.

I’ll look a bit more into it, but it should definitely be possible to fix it. Hopefully I’ll figure something out, and respond with whatever solution I find - but in the meantime, if anyone has a clue, I’d appreciate pointers :raised_hands: