Skip to content
Snippets Groups Projects
vector_tile_fix.js 5.53 KiB
import L from 'leaflet';
export var Symbolizer = L.Class.extend({
  // 🍂method initialize(feature: GeoJSON, pxPerExtent: Number)
  // Initializes a new Line Symbolizer given a GeoJSON feature and the
  // pixel-to-coordinate-units ratio. Internal use only.

  // 🍂method render(renderer, style)
  // Renders this symbolizer in the given tiled renderer, with the given
  // `L.Path` options.  Internal use only.
  render: function(renderer, style) {
    this._renderer = renderer;
    this.options = style;
    renderer._initPath(this);
    renderer._updateStyle(this);
  },

  // 🍂method render(renderer, style)
  // Updates the `L.Path` options used to style this symbolizer, and re-renders it.
  // Internal use only.
  updateStyle: function(renderer, style) {
    this.options = style;
    renderer._updateStyle(this);
  },

  _getPixelBounds: function() {
    var parts = this._parts;
    var bounds = L.bounds([]);
    for (var i = 0; i < parts.length; i++) {
      var part = parts[i];
      for (var j = 0; j < part.length; j++) {
        bounds.extend(part[j]);
      }
    }

    var w = this._clickTolerance(),
      p = new L.Point(w, w);

    bounds.min._subtract(p);
    bounds.max._add(p);

    return bounds;
  },
  _clickTolerance: L.Path.prototype._clickTolerance,
});

export var PolyBase = {
  _makeFeatureParts: function(feat, pxPerExtent) {
    var rings = feat.geometry;
    var coord;

    this._parts = [];
    for (var i = 0; i < rings.length; i++) {
      var ring = rings[i];
      var part = [];
      for (var j = 0; j < ring.length; j++) {
        coord = ring[j];
        // Protobuf vector tiles return {x: , y:}
        // Geojson-vt returns [,]
        part.push(L.point(coord).scaleBy(pxPerExtent));
      }
      this._parts.push(part);
    }
  },

  makeInteractive: function() {
    this._pxBounds = this._getPixelBounds();
  }
};
export var LineSymbolizer = L.Polyline.extend({
  includes: [Symbolizer.prototype, PolyBase],

  initialize: function(feature, pxPerExtent) {
    this.properties = feature.properties;
    this._makeFeatureParts(feature, pxPerExtent);
  },

  render: function(renderer, style) {
    style.fill = false;
    Symbolizer.prototype.render.call(this, renderer, style);
    this._updatePath();
  },

  updateStyle: function(renderer, style) {
    style.fill = false;
    Symbolizer.prototype.updateStyle.call(this, renderer, style);
  },
});
export var FillSymbolizer = L.Polygon.extend({
  includes: [Symbolizer.prototype, PolyBase],

  initialize: function(feature, pxPerExtent) {
    this.properties = feature.properties;
    this._makeFeatureParts(feature, pxPerExtent);
  },

  render: function(renderer, style) {
    Symbolizer.prototype.render.call(this, renderer, style);
    this._updatePath();
  }
});
export var PointSymbolizer = L.CircleMarker.extend({
  includes: Symbolizer.prototype,

  statics: {
    iconCache: {}
  },

  initialize: function(feature, pxPerExtent) {
    this.properties = feature.properties;
    this._makeFeatureParts(feature, pxPerExtent);
  },

  render: function(renderer, style) {
    Symbolizer.prototype.render.call(this, renderer, style);
    this._radius = style.radius || L.CircleMarker.prototype.options.radius;
    this._updatePath();
  },

  _makeFeatureParts: function(feat, pxPerExtent) {
    var coord = feat.geometry[0];
    if (typeof coord[0] === 'object' && 'x' in coord[0]) {
      // Protobuf vector tiles return [{x: , y:}]
      this._point = L.point(coord[0]).scaleBy(pxPerExtent);
      this._empty = L.Util.falseFn;
    } else {
      // Geojson-vt returns [,]
      this._point = L.point(coord).scaleBy(pxPerExtent);
      this._empty = L.Util.falseFn;
    }
  },

  makeInteractive: function() {
    this._updateBounds();
  },

  updateStyle: function(renderer, style) {
    this._radius = style.radius || this._radius;
    this._updateBounds();
    return Symbolizer.prototype.updateStyle.call(this, renderer, style);
  },

  _updateBounds: function() {
    var icon = this.options.icon;
    if (icon) {
      var size = L.point(icon.options.iconSize),
        anchor = icon.options.iconAnchor ||
                size && size.divideBy(2, true),
        p = this._point.subtract(anchor);
      this._pxBounds = new L.Bounds(p, p.add(icon.options.iconSize));
    } else {
      L.CircleMarker.prototype._updateBounds.call(this);
    }
  },

  _updatePath: function() {
    if (this.options.icon) {
      this._renderer._updateIcon(this);
    } else {
      L.CircleMarker.prototype._updatePath.call(this);
    }
  },

  _getImage: function () {
    if (this.options.icon) {
      var url = this.options.icon.options.iconUrl,
        img = PointSymbolizer.iconCache[url];
      if (!img) {
        var icon = this.options.icon;
        img = PointSymbolizer.iconCache[url] = icon.createIcon();
      }
      return img;
    } else {
      return null;
    }

  },

  _containsPoint: function(p) {
    var icon = this.options.icon;
    if (icon) {
      return this._pxBounds.contains(p);
    } else {
      return L.CircleMarker.prototype._containsPoint.call(this, p);
    }
  }
});

L.VectorGrid.prototype._createLayer=function(feat, pxPerExtent) {
  var layer;
  switch (feat.type) {
  case 1:
    layer = new PointSymbolizer(feat, pxPerExtent);
    // [YB 2019-10-23: prevent leaflet from treating these canvas points as real markers]
    layer.getLatLng = null;         
    break;
  case 2:
    layer = new LineSymbolizer(feat, pxPerExtent);
    break;
  case 3:
    layer = new FillSymbolizer(feat, pxPerExtent);
    break;
  }
  
  if (this.options.interactive) {
    layer.addEventParent(this);
  }
  
  return layer;
};