Skip to content

Vector Shapes

This page documents the concrete vector shape classes in Leaflet: Polyline, Polygon, Circle, CircleMarker, and Rectangle. These classes extend the Path base class and represent geometric shapes drawn as vectors on the map. Each shape class handles coordinate conversion, bounds calculation, projection, and geometry-specific operations.

For information about the vector rendering system (Canvas and SVG renderers), see Vector Rendering System. For the base Path class and shared functionality, see Vector Layers.


Class Hierarchy

All vector shapes extend from the Path base class, which provides common styling and rendering integration. The hierarchy is organized by geometric type:

SVG
100%

Shape Comparison

ShapeExtendsCoordinate TypeRadius TypeSupports MultiSupports Holes
PolylinePathArray of LatLngN/AYesNo
PolygonPolylineArray of arraysN/AYesYes
RectanglePolygonLatLngBoundsN/ANoNo
CircleMarkerPathSingle LatLngPixelsNoNo
CircleCircleMarkerSingle LatLngMetersNoNo

Coordinate Structure Patterns

Vector shapes support different levels of coordinate nesting to represent simple shapes, multi-part shapes, and shapes with holes:

SVG
100%

Polyline

The Polyline class draws lines connecting geographic points. It supports both simple polylines (single line) and MultiPolyline (multiple separate lines).

Key Methods

MethodDescriptionReturn Type
getLatLngs()Returns the array of points or nested arrays for multi-polylineLatLng[] or LatLng[][]
setLatLngs(latlngs)Replaces all points and redrawsthis
addLatLng(latlng, latlngs?)Adds a point, optionally to a specific ringthis
isEmpty()Returns true if no pointsBoolean
getBounds()Returns the bounding boxLatLngBounds
getCenter()Returns the centroidLatLng
closestLayerPoint(p)Finds closest point on the line to given pointPoint

Options

{
  smoothFactor: 1.0,  // Simplification tolerance (higher = more simplified)
  noClip: false       // Disable polyline clipping for performance
}

Internal Coordinate Processing

The Polyline class performs several transformations on coordinates:

SVG
100%

Implementation Details

Coordinate Conversion (src/layer/vector/Polyline.js158-172):

  • Recursively converts input arrays to LatLng instances
  • Determines if array is flat (single line) or nested (multi-line) using LineUtil.isFlat()
  • Calculates and extends _bounds during conversion

Projection (src/layer/vector/Polyline.js174-210):

  • Converts geographic coordinates to pixel coordinates via map.latLngToLayerPoint()
  • Creates _rings array of projected coordinate arrays
  • Maintains _rawPxBounds for the unprojected bounds

Clipping (src/layer/vector/Polyline.js213-247):

  • Clips line segments to renderer bounds using LineUtil.clipSegment()
  • Creates _parts array containing visible segments
  • Skipped if noClip: true option is set

Simplification (src/layer/vector/Polyline.js250-257):

  • Applies Douglas-Peucker algorithm via LineUtil.simplify()
  • Controlled by smoothFactor option
  • Reduces point count for performance while maintaining visual accuracy

Hit Detection (src/layer/vector/Polyline.js272-291):

  • Used by Canvas renderer for interactivity
  • Checks if point is within _clickTolerance() of any line segment
  • Uses LineUtil.pointToSegmentDistance() for distance calculation

Polygon

The Polygon class extends Polyline to draw closed shapes. It supports holes (interior rings) and MultiPolygon geometries.

Key Methods

MethodDescriptionNotes
isEmpty()Returns true if no rings or first ring is emptyOverrides Polyline version
getCenter()Returns polygon centroidUses PolyUtil.polygonCenter()

Coordinate Structure

Polygons use a more complex nesting structure than polylines:

  • Simple Polygon: [[[lat,lng], [lat,lng], ...]] - Single outer ring wrapped in array
  • Polygon with Holes: First array is outer ring, subsequent arrays are holes
  • MultiPolygon: Each element is a polygon (which itself can have holes)
SVG
100%

Implementation Details

Coordinate Normalization (src/layer/vector/Polygon.js76-92):

  • Ensures _latlngs is never flat (always wrapped in at least one array)
  • Removes duplicate last point if it equals the first point
  • First ring is always the outer boundary, others are holes

Clipping Algorithm (src/layer/vector/Polygon.js98-124):

  • Uses PolyUtil.clipPolygon() instead of line segment clipping
  • Expands clip bounds by stroke width to avoid edge artifacts
  • Clips each ring independently

Hit Detection (src/layer/vector/Polygon.js131-153):

  • Uses ray casting algorithm to check if point is inside polygon
  • Falls back to Polyline's _containsPoint() to check stroke
  • Handles holes by alternating inside/outside state

Circle and CircleMarker

These classes provide two different types of circular shapes with fundamentally different coordinate systems.

CircleMarker: Fixed Pixel Radius

CircleMarker draws a circle with a fixed pixel radius that doesn't scale with zoom level. Useful for markers and point features.

Key Characteristics:

  • Radius specified in pixels
  • Radius stays constant across zoom levels
  • Simple projection: just converts center point to layer coordinates

Options:

{
  fill: true,
  radius: 10  // pixels
}

Circle: Geographic Radius

Circle draws a circle with a radius in meters, accounting for map projection. The pixel radius changes with zoom and latitude.

Key Characteristics:

  • Radius specified in meters (geographic distance)
  • Pixel size varies with zoom level and latitude
  • Complex projection calculations for Earth CRS

Options:

{
  radius: 200  // meters (required)
}

Circle Projection Comparison

SVG
100%

Circle Earth Projection Details

For Earth CRS (Web Mercator), Circle performs sophisticated calculations (src/layer/vector/Circle.js76-92):

  1. Calculate latitude radius in degrees from meter radius:

    latR = (meters / Earth.R) / (π/180)
  2. Project top and bottom points at [lat ± latR, lng]

  3. Calculate center and adjusted latitude from projected points

  4. Calculate longitude radius using spherical trigonometry:

    cos(latR) = cos(lat) * cos(lat2) * cos(lngR) + sin(lat) * sin(lat2)
  5. Handle edge cases: Falls back to simplified calculation near poles

  6. Store ellipse parameters: _radius (x), _radiusY (y) for non-circular projection

This accounts for the fact that circles on the Earth's surface project as ellipses in Web Mercator projection, with distortion increasing at higher latitudes.

Methods Comparison

MethodCircleMarkerCircle
setRadius(radius)PixelsMeters
getRadius()Returns pixel radiusReturns meter radius
setLatLng(latlng)✓ (inherited)
getLatLng()✓ (inherited)
getBounds()Pixel-based boundsGeographic bounds

Rectangle

The Rectangle class is a specialized Polygon that creates a four-cornered shape from a LatLngBounds object.

Constructor and Methods

// Create from LatLngBounds
const bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
const rectangle = new Rectangle(bounds, {color: "#ff7800", weight: 1});

// Update bounds
rectangle.setBounds(newBounds);

Internal Implementation

Bounds to Coordinates Conversion (src/layer/vector/Rectangle.js41-49):

The _boundsToLatLngs() method converts a LatLngBounds to four corner points in counter-clockwise order:

  1. South-West corner
  2. North-West corner
  3. North-East corner
  4. South-East corner

This creates a properly oriented polygon for the renderer.

SVG
100%

Common Operations

All vector shapes share certain operations inherited from Path and implemented in shape-specific ways.

Bounds Calculation

Each shape calculates its bounding box differently:

ShapeBounds Calculation
PolylineExtends bounds for each point during conversion
PolygonInherits from Polyline
CircleMarkerCenter ± radius in pixels
CircleProjects center ± radius to LatLng bounds
RectangleDefined by constructor LatLngBounds

Center Calculation

SVG
100%

Notes:

  • Polyline and Polygon getCenter() require the shape to be added to the map first (throws error otherwise)
  • This is because center calculation requires projected coordinates via the map's CRS
  • Circles simply return their center point

Hit Detection

Hit detection is used by the Canvas renderer to determine if a mouse/touch event intersects the shape:

ShapeAlgorithmImplementation
PolylinePoint-to-segment distanceLineUtil.pointToSegmentDistance() ≤ tolerance
PolygonRay casting + stroke checkCount edge crossings, then check Polyline
CircleMarkerDistance checkpoint.distanceTo(center) ≤ radius
CircleDistance checkInherited from CircleMarker

Performance Optimizations

Vector shapes employ several optimizations to maintain performance with large datasets.

Clipping

Purpose: Reduce rendering workload by excluding geometry outside the visible area.

Implementation:

Process:

SVG
100%

Simplification

Purpose: Reduce point count while maintaining visual accuracy using the Douglas-Peucker algorithm.

Configuration:

  • Controlled by smoothFactor option (default: 1.0)
  • Higher values = more aggressive simplification
  • Applied after clipping via LineUtil.simplify()

Trade-offs:

  • Higher smoothFactor: Better performance, less detail
  • Lower smoothFactor: More detail, slower rendering
  • Value of 0 disables simplification
// Heavy simplification (faster, less accurate)
const polyline1 = new Polyline(coords, {smoothFactor: 3.0});

// Minimal simplification (slower, more accurate)  
const polyline2 = new Polyline(coords, {smoothFactor: 0.5});

// No simplification (slowest, exact)
const polyline3 = new Polyline(coords, {smoothFactor: 0});

Update Pipeline

The complete update pipeline for polyline-based shapes:

SVG
100%

File Reference Summary

Core Implementation Files

Test Files