Skip to content

Vector Rendering System

Purpose and Scope

This document explains the vector rendering system in Leaflet, which is responsible for drawing vector shapes (polylines, polygons, circles, etc.) to the screen. The system provides two rendering strategies: Canvas-based rendering for pixel manipulation and SVG-based rendering using DOM elements. For information about the vector shape classes themselves (Polyline, Polygon, Circle), see Vector Shapes.

The rendering system is built on three core components:

  • Renderer base class: Manages renderer lifecycle and coordinate transformations
  • Canvas renderer: Pixel-based rendering with manual hit detection
  • SVG renderer: DOM-based rendering with native browser events

Architecture Overview

SVG
100%

Renderer Base Class

The Renderer class extends BlanketOverlay and provides the foundation for both Canvas and SVG implementations. It manages a collection of path layers and coordinates their rendering lifecycle.

Core Responsibilities

ResponsibilityImplementation
Layer trackingMaintains _layers object mapping stamped layer IDs to layer instances
Coordinate updatesRecalculates layer coordinates on zoom end via _onZoomEnd()
Rendering updatesTriggers layer updates via _updatePaths() on 'update' event
View resetsHandles view reset by calling _reset() on all layers

Lifecycle Integration

SVG
100%

The renderer listens for map events and translates them into coordinate updates. When the map moves or zooms, the renderer ensures all paths recalculate their pixel positions via _project() and redraw via _update().

Canvas Renderer

The Canvas renderer uses HTML5 Canvas 2D context for pixel-based drawing. Unlike SVG, Canvas does not create individual DOM elements for each shape, requiring custom implementations for hit detection and z-ordering.

Container Initialization

The Canvas renderer creates a <canvas> element and attaches pointer event listeners:

SVG
100%

The canvas handles retina displays by scaling the internal canvas size by window.devicePixelRatio while maintaining the CSS display size:

Drawing Order Management

Canvas maintains drawing order using a doubly-linked list structure. Each layer receives an _order object containing references to the previous and next layers:

SVG
100%

This structure enables efficient reordering operations for bringToFront() and bringToBack():

OperationImplementationComplexity
_initPath()Append to end of listO(1)
_bringToFront()Move to _drawLast positionO(1)
_bringToBack()Move to _drawFirst positionO(1)
_removePath()Unlink from listO(1)

Rendering Pipeline

The Canvas renderer uses a request-based redraw system with dirty rectangle optimization:

SVG
100%

The _redrawBounds optimization only clears and redraws the portion of the canvas that changed, reducing rendering cost for localized updates:

Hit Detection

Canvas requires manual hit detection since drawn pixels have no individual identity. The renderer iterates through layers in drawing order and tests point containment:

SVG
100%

The _containsPoint() method is implemented by each Path subclass and includes tolerance for stroke width:

The renderer throttles pointer hover detection to 32ms to avoid performance degradation during rapid mouse movement:

Drawing Primitives

The Canvas renderer provides two core drawing methods:

MethodPurposeKey Operations
_updatePoly(layer, closed)Draw polylines/polygonsctx.beginPath(), ctx.moveTo(), ctx.lineTo(), optional ctx.closePath()
_updateCircle(layer)Draw circlesctx.arc(), handles elliptical scaling via ctx.scale()

Both methods delegate to _fillStroke() for applying styles:

SVG Renderer

The SVG renderer creates individual SVG <path> elements for each vector layer, leveraging the browser's native event handling and rendering.

Container Structure

SVG
100%

The SVG container uses viewBox to position paths without modifying their coordinates:

Path Element Creation

When a layer is initialized, the SVG renderer creates a <path> element with appropriate classes and interactivity:

SVG
100%

Style Application

The SVG renderer applies styles by setting SVG attributes directly on the path element:

Style CategorySVG Attributes
Strokestroke, stroke-opacity, stroke-width, stroke-linecap, stroke-linejoin
Dash patternstroke-dasharray, stroke-dashoffset
Fillfill, fill-opacity, fill-rule

Path Data Generation

The SVG renderer converts coordinates to SVG path data strings:

SVG
100%

For circles, the renderer uses SVG arc commands to draw two half-circles:

Z-Index Management

Since SVG does not support z-index, the SVG renderer manages layer order by reordering DOM elements:

OperationImplementation
_bringToFront()Move path element to end of parent using DomUtil.toFront()
_bringToBack()Move path element to start of parent using DomUtil.toBack()

Event Handling

Unlike Canvas, SVG paths receive native browser events. The SVG renderer marks interactive paths with the leaflet-interactive class and calls addInteractiveTarget() to integrate with Leaflet's event system:

Path-Renderer Integration

The Path class coordinates with renderers through a well-defined interface:

SVG
100%

Renderer Selection

Maps can specify a default renderer, or individual paths can use explicit renderers:

// Map-level default renderer
const map = new LeafletMap('map', {
    renderer: new Canvas()
});

// Path-specific renderer
const myRenderer = new SVG({ padding: 0.5 });
const line = new Polyline(coords, { renderer: myRenderer });

Renderer Comparison

AspectCanvasSVG
DOM ElementsSingle <canvas> elementIndividual <path> per layer
Event HandlingManual hit detection via _containsPoint()Native browser events
Drawing OrderDoubly-linked listDOM element order
Z-Index ChangesO(1) list manipulation + redrawO(1) DOM reordering
RenderingImmediate mode (clear + redraw)Retained mode (browser manages)
MemoryFixed canvas sizeScales with layer count
Hit DetectionO(n) iteration through layersO(1) browser native
Styling UpdatesRedraw requiredAttribute changes only
Partial UpdatesDirty rectangle optimizationPer-element invalidation

Performance Considerations

Canvas Optimizations

  1. Redraw Bounds: Only clears and redraws the affected rectangle

  2. Request Animation Frame: Batches multiple update requests into single frame

  3. Hover Throttling: Limits pointer move processing to 32ms intervals

  4. Device Pixel Ratio: Renders at device resolution for retina displays

SVG Optimizations

  1. ViewBox Updates: Moves all paths together without coordinate recalculation

  2. Attribute Updates: Changes styles without full re-render

  3. Native Events: Leverages browser's built-in event handling

Common Optimizations

Both renderers:

  • Use padding to extend container bounds and reduce edge clipping
  • Defer updates during zoom animations
  • Batch coordinate updates on zoom end

Coordinate Transformation

The renderer's coordinate system uses pixel coordinates relative to the map's pixel origin. When the map moves, the renderer updates its transform rather than recalculating all layer coordinates:

Canvas Transform:

// Translate canvas context to align with map bounds
this._ctx.setTransform(
    s, 0, 0, s,
    -b.min.x * s,
    -b.min.y * s
);

SVG ViewBox:

// Update viewBox to shift all paths together
this._container.setAttribute('viewBox', 
    [b.min.x, b.min.y, size.x, size.y].join(' ')
);