title: Markers extended from CircleMarker - How to change the click area?
body: <p>With Leaflet, I'm trying to render a lot of points (+ 10000) as a GeoJSON feature to improve performance. In order to achieve better results, I found <a href="https://stackoverflow.com/a/51852641/11064013">this answer</a> instructing on how to extend Leaflet's <code>circleMarker</code> to change it's shape like so:</p>
  
  <pre><code>L.Canvas.include({
      _updateMarkerPin: function(layer) {
          if (!this._drawing || layer._empty()) {
              return
          }
  
          var p = layer._point,
              ctx = this._ctx,
              r = layer._radius
  
          this._drawnLayers[layer._leaflet_id] = layer
  
          ctx.beginPath()
          ctx.moveTo(p.x, p.y)
          ctx.lineTo(p.x - 0.58 * r, p.y - r)
          ctx.arc(p.x, p.y - 2 * r, r, -Math.PI * 1.161, Math.PI * 0.161)
          ctx.closePath()
          this._fillStroke(ctx, layer)
      },
  })
  
  const MarkerPin = L.CircleMarker.extend({
      _updatePath: function() {
          this._renderer._updateMarkerPin(this)
      },
  })
  </code></pre>
  
  <p>This is my MarkerPin Shape:</p>
  
  <p><a href="https://i.stack.imgur.com/8aiJX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8aiJX.png" alt="MarkerPin"></a></p>
  
  <p><code>MarkerPin</code> is then used in <code>L.GeoJSON</code>'s <code>pointToLayer</code> option as follows:</p>
  
  <pre><code>const myPointToLayer = (feature, latlng) =&gt; {
      var markerParams = {
          radius: 16,
          stroke: true,
          weight: 2,
          opacity: 0.4,
          fillOpacity: 0.9,
      }
      return new MarkerPin(latlng, markerParams)
  }
  
  const myOnEachFeature = (feature, layer) =&gt; {
      layer.bindPopup('Clicked me!')
  }
  
  L.geoJSON(data, {
      pointToLayer:myPointToLayer,
      onEachFeature: myOnEachFeature,
  }).addTo(map);
  </code></pre>
  
  <p>So far so good. All the data gets rendered properly.
  My problem is: the click area isn't updated according to my new shape, it stays like the <code>circleMarker</code>'s one (because that's what I've extended to create my pin) illustrated by the red circle:</p>
  
  <p><a href="https://i.stack.imgur.com/Fo0ux.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Fo0ux.png" alt="MarkerPin click area"></a></p>
  
  <p>Other Leaflet elements, like polygons, have their click area match their shape. That being said, is it possible to change the click area of my <code>MarkerPin</code> to match my shape (even if I'm extending <code>circleMarker</code>)?</p>
  
  <p>Even if it's not possible to change the shape of the click area, I'd be satisfied to being able to move it up a bit like the image below:</p>
  
  <p><a href="https://i.stack.imgur.com/uyl7o.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/uyl7o.png" alt="MarkerPin recentered click area"></a></p>
  
  <p>Or even, is there a better approach to render several markers in GeoJSON with a custom icon and handle their popups with Leaflet?</p>
  
  <p><strong>Edit</strong></p>
  
  <p>For completeness, this is what I'm using (thanks to <a href="https://stackoverflow.com/a/56072877/11064013">https://stackoverflow.com/a/56072877/11064013</a>), which uses the whole pin area:</p>
  
  <pre><code>const MarkerPin = L.CircleMarker.extend({
      _updatePath: function() {
          this._renderer._updateMarkerPin(this)
      },
      _containsPoint: function(p) {
          let r = this._radius
  
          let insideCircle =
              p.add([0, r * 2]).distanceTo(this._point) &lt;= r + this._clickTolerance()
  
          let a = this._point,
              b = a.subtract([0.58 * r, r]),
              c = a.subtract([-0.58 * r, r])
  
          let insideTriangle = true
  
          let ap_x = p.x - a.x
          let ap_y = p.y - a.y
  
          let p_ab = (b.x - a.x) * ap_y - (b.y - a.y) * ap_x &gt; 0
          let p_ac = (c.x - a.x) * ap_y - (c.y - a.y) * ap_x &gt; 0
          let p_bc = (c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x) &gt; 0
  
          if (p_ac === p_ab) {
              insideTriangle = false
          }
          if (p_bc !== p_ab) {
              insideTriangle = false
          }
          return insideTriangle || insideCircle
      },
  })
  </code></pre>