【问题标题】:Challenge for polygon display within leaflet传单内多边形显示的挑战
【发布时间】:2020-07-01 05:36:33
【问题描述】:

我们在传单(最新版本)中的多边形显示方面遇到了特定的设计挑战。

我们使用实心边框和半透明背景渲染多边形。 我们正在寻找一种方法来绘制实心边框以及更宽的“内嵌”边框且无背景。

注意:问题是针对不是矩形的多边形。下图 代码只是举例。

有什么办法可以做到吗?

var polygon = L.polygon([
  [ 51.72872938200587, -2.415618896484375 ],
  [ 51.72872938200587, -2.080535888671875 ],
  [ 51.901918172561714, -2.080535888671875 ],
  [ 51.901918172561714, -2.415618896484375 ],
  [ 51.72872938200587, -2.415618896484375 ]

],{
 color:'#2F538F',
 fillOpacity: 0.9,
 fillColor: '#BFBFBF',
}).addTo(map);

【问题讨论】:

    标签: javascript leaflet gis


    【解决方案1】:

    这可以通过利用 leaflet 的类 extension 系统来实现。

    首先,可以咨询传单的class diagram 以确定需要扩展的位置。作为一般规则,首先尝试将类扩展到根目录,并且更喜欢 L.Class.extend 而不是 L.Class.include

    工作解决方案:

    Codesandbox

    一种方法是连接到渲染过程。在以下示例中,L.Canvas 扩展为自定义 L.Canvas.WithExtraStyles 类(leaflet 的插件构建 guidelines)。然后将自定义的Renderer 提供给地图。

    在这种方法中,请注意,可以使用 extraStyles 配置提供多个边框和填充(插入和开始)。

    extraStyle 自定义属性接受 Array of PathOptions。使用额外的inset,其值可以是正数或负数像素,表示偏移形成主要几何图形的边界。 inset 的负值会将边界置于原始多边形之外。

    在实施此类自定义时,必须特别注意确保传单不会将添加的自定义视为单独的几何形状。否则交互功能,例如多边形编辑或传单绘制会出现意外行为

    // CanvasWithExtraStyles.js
    // First step is to provide a special renderer which accept configuration for extra borders.
    // Here L.Canvas is extended using Leaflet's class system
    const styleProperties = ['stroke', 'color', 'weight', 'opacity', 'fill', 'fillColor', 'fillOpacity'];
    
    /*
     * @class Polygon.MultiStyle
     * @aka L.Polygon.MultiStyle
     * @inherits L.Polygon
     */
    L.Canvas.WithExtraStyles = L.Canvas.extend({
      _updatePoly: function(layer, closed) {
        const centerCoord = layer.getCenter();
        const center = this._map.latLngToLayerPoint(centerCoord);
        const originalParts = layer._parts.slice();
    
        // Draw extra styles
        if (Array.isArray(layer.options.extraStyles)) {
          const originalStyleProperties = styleProperties.reduce(
            (acc, cur) => ({ ...acc, [cur]: layer.options[cur] }),
            {}
          );
          const cx = center.x;
          const cy = center.y;
    
          for (let eS of layer.options.extraStyles) {
            const i = eS.inset || 0;
    
            // For now, the algo doesn't support MultiPolygon
            // To have it support MultiPolygon, find centroid
            // of each MultiPolygon and perform the following
            layer._parts[0] = layer._parts[0].map(p => {
              return {
                x: p.x < cx ? p.x + i : p.x - i,
                y: p.y < cy ? p.y + i : p.y - i
              };
            });
    
            //Object.keys(eS).map(k => layer.options[k] = eS[k]);
            Object.keys(eS).map(k => (layer.options[k] = eS[k]));
            L.Canvas.prototype._updatePoly.call(this, layer, closed);
          }
    
          // Resetting original conf
          layer._parts = originalParts;
          Object.assign(layer.options, originalStyleProperties);
        }
    
        L.Canvas.prototype._updatePoly.call(this, layer, closed);
      }
    });
    // Leaflet's conventions to also provide factory methods for classes
    L.Canvas.withExtraStyles = function(options) {
      return new L.Canvas.WithExtraStyles(options);
    };
    
    
    // --------------------------------------------------------------
    
    // map.js
    const map = L.map("map", {
      center: [52.5145206, 13.3499977],
      zoom: 18,
      renderer: new L.Canvas.WithExtraStyles()
    });
    
    new L.tileLayer(
      "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}.png",
      {
        attribution: `attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attribution">CARTO</a>`,
        detectRetina: true
      }
    ).addTo(map);
    
    // Map center
    const { x, y } = map.getSize();
    
    // Left Polygon
    const polyStyle1 = {
      color: '#2f528f',
      extraStyles: [
        {
          color: 'transparent',
          weight: 10,
          fillColor: '#d9d9d9'
        }
      ]
    };
    
    // Sudo coordinates are generated form map container pixels
    const polygonCoords1 = [
      [0, 10],
      [300, 10],
      [300, 310],
      [0, 310]
    ].map(point => map.containerPointToLatLng(point));
    const polygon1 = new L.Polygon(polygonCoords1, polyStyle1);
    polygon1.addTo(map);
    
    // Right Polygon
    const polyStyle2 = {
      fillColor: "transparent",
      color: '#2f528f',
      extraStyles: [
        {
          inset: 6,
          color: '#d9d9d9',
          weight: 10
        }
      ]
    };
    
    const polygonCoords2 = [
      [340, 10],
      [640, 10],
      [640, 310],
      [340, 310]
    ].map(point => map.containerPointToLatLng(point));
    const polygon2 = new L.Polygon(polygonCoords2, polyStyle2);
    polygon2.addTo(map);
    <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" rel="stylesheet"/>
    
    <div id="map" style="width: 100vw; height: 100vw">0012</div>

    理想解决方案:

    • 将插件实现为单独的 npm 模块。
    • 尝试扩展或挂钩到 Renderer 本身,而不是单独扩展 L.Canvas 和 L.SVG。
    • 将自定义挂钩到基类 Path,而不是单独的形状:多边形、折线或圆形。

    【讨论】:

      【解决方案2】:

      使用 Recatngle/Polygon 方法。

      // define rectangle geographical bounds
      var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
      // create an orange rectangle
      L.rectangle(bounds, {}).addTo(map);
      

      使用选项在线条上获得所需的效果。选项继承自polyline options

      您可以在此处调整 coloropacityfillfillColorfillOpacityfillRule 以获得所需的线条效果

      【讨论】:

      • 谢谢,但是它是一个多边形,而不是一个矩形,有问题的图像和代码只是示例。
      • 您也可以对多边形使用相同的折线选项。它们都继承自同一个基类。
      • 是的,我们可以使用选项,但如果形状不是确切的矩形怎么办。它可以是六边形
      • 您可以使用多边形获得任何形状。并使用选项以您想要的方式塑造线条。
      猜你喜欢
      • 1970-01-01
      • 2021-04-05
      • 2018-02-03
      • 2016-02-06
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多