or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

clipping.mdgeographic-calculations.mdindex.mdpath.mdprojections.mdshapes.mdtransformations.md
tile.json

path.mddocs/

Path Generation

SVG and Canvas path generation for rendering GeoJSON features with integrated projection support. The path generator transforms GeoJSON geometries into renderable paths for creating interactive maps and geographic visualizations.

Capabilities

Path Generator Factory

Creates a path generator that converts GeoJSON geometries to SVG path strings or Canvas drawing commands.

/**
 * Creates a path generator for rendering GeoJSON features
 * @param projection - Optional projection to transform coordinates (null for identity)
 * @param context - Optional Canvas context for drawing (null for SVG string output)
 * @returns Path generator instance
 */
function geoPath(projection?: Projection | null, context?: CanvasRenderingContext2D | null): Path;

interface Path {
  /**
   * Generates a path string or draws to canvas for the specified GeoJSON object
   * @param object - GeoJSON feature or geometry
   * @returns SVG path string (if no context) or null (if canvas context)
   */
  (object: GeoJSON.Feature | GeoJSON.Geometry): string | null;
  
  /**
   * Computes the projected planar area of the specified GeoJSON object
   * @param object - GeoJSON feature or geometry
   * @returns Area in square pixels
   */
  area(object: GeoJSON.Feature | GeoJSON.Geometry): number;
  
  /**
   * Computes the projected planar bounding box of the specified GeoJSON object
   * @param object - GeoJSON feature or geometry
   * @returns Bounding box as [[x0, y0], [x1, y1]]
   */
  bounds(object: GeoJSON.Feature | GeoJSON.Geometry): [[number, number], [number, number]];
  
  /**
   * Computes the projected planar centroid of the specified GeoJSON object
   * @param object - GeoJSON feature or geometry
   * @returns Centroid as [x, y]
   */
  centroid(object: GeoJSON.Feature | GeoJSON.Geometry): [number, number];
  
  /**
   * Computes the projected planar length of the specified GeoJSON object
   * @param object - GeoJSON feature or geometry
   * @returns Length in pixels
   */
  measure(object: GeoJSON.Feature | GeoJSON.Geometry): number;
  
  /**
   * Sets or gets the path generator's projection
   * @param projection - Projection function or null for identity
   * @returns This path generator or current projection
   */
  projection(projection?: Projection | null): this | Projection | null;
  
  /**
   * Sets or gets the path generator's rendering context
   * @param context - Canvas context or null for string output
   * @returns This path generator or current context
   */
  context(context?: CanvasRenderingContext2D | null): this | CanvasRenderingContext2D | null;
  
  /**
   * Sets or gets the radius for rendering Point and MultiPoint geometries
   * @param radius - Point radius in pixels or function that returns radius
   * @returns This path generator or current point radius
   */
  pointRadius(radius?: number | ((object: any, ...args: any[]) => number)): this | number | ((object: any, ...args: any[]) => number);
  
  /**
   * Sets or gets the number of fractional digits for string output
   * @param digits - Number of digits or null for maximum precision
   * @returns This path generator or current digits setting
   */
  digits(digits?: number | null): this | number | null;
}

Usage Examples

SVG Path Generation

import { geoPath, geoMercator } from "d3-geo";

// Create projection and path generator
const projection = geoMercator()
  .scale(150)
  .translate([480, 250]);

const path = geoPath(projection);

// Generate SVG paths for GeoJSON features
const countries = {
  type: "FeatureCollection",
  features: [/* country polygons */]
};

// Create SVG elements
const svg = d3.select("body").append("svg")
  .attr("width", 960)
  .attr("height", 500);

svg.selectAll("path")
  .data(countries.features)
  .enter().append("path")
  .attr("d", path) // path generator creates d attribute
  .attr("fill", "steelblue")
  .attr("stroke", "white");

Canvas Rendering

import { geoPath, geoOrthographic } from "d3-geo";

// Setup canvas
const canvas = d3.select("body").append("canvas")
  .attr("width", 960)
  .attr("height", 500);

const context = canvas.node().getContext("2d");

// Create projection and path generator with canvas context
const projection = geoOrthographic()
  .scale(250)
  .translate([480, 250]);

const path = geoPath(projection, context);

// Draw to canvas
function render(countries) {
  context.clearRect(0, 0, 960, 500);
  
  context.beginPath();
  path({type: "Sphere"}); // Draw sphere outline
  context.strokeStyle = "#ccc";
  context.stroke();
  
  countries.features.forEach(country => {
    context.beginPath();
    path(country); // Draw country
    context.fillStyle = "steelblue";
    context.fill();
    context.strokeStyle = "white";
    context.stroke();
  });
}

Dynamic Point Radius

import { geoPath, geoAlbers } from "d3-geo";

const projection = geoAlbers();
const path = geoPath(projection);

// Set dynamic point radius based on feature properties
path.pointRadius((d) => {
  if (d.properties && d.properties.population) {
    return Math.sqrt(d.properties.population / 100000);
  }
  return 3; // default radius
});

// Render cities with population-based sizing
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      properties: { name: "New York", population: 8000000 },
      geometry: { type: "Point", coordinates: [-74, 40.7] }
    },
    // ... more cities
  ]
};

svg.selectAll(".city")
  .data(cities.features)
  .enter().append("path")
  .attr("class", "city")
  .attr("d", path);

Path Measurements

import { geoPath, geoMercator } from "d3-geo";

const projection = geoMercator().scale(1000);
const path = geoPath(projection);

const polygon = {
  type: "Polygon",
  coordinates: [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]
};

const lineString = {
  type: "LineString",
  coordinates: [[0, 0], [1, 0], [1, 1]]
};

// Calculate projected measurements
const area = path.area(polygon);        // Area in square pixels
const bounds = path.bounds(polygon);    // Bounding box [[x0,y0], [x1,y1]]
const centroid = path.centroid(polygon); // Centroid [x, y]
const length = path.measure(lineString); // Length in pixels

console.log(`Projected area: ${area} square pixels`);
console.log(`Bounds: ${bounds}`);
console.log(`Centroid: ${centroid}`);
console.log(`Length: ${length} pixels`);

Precision Control

import { geoPath, geoMercator } from "d3-geo";

const projection = geoMercator();
const path = geoPath(projection);

// Control decimal precision for SVG output
path.digits(2); // Limit to 2 decimal places

const feature = {
  type: "Polygon",
  coordinates: [[[0, 0], [0.123456, 0], [0.123456, 0.123456], [0, 0.123456], [0, 0]]]
};

const pathString = path(feature);
// Output will have coordinates rounded to 2 decimal places
console.log(pathString); // "M0,250L73.23,250L73.23,236.16L0,236.16Z"

// Use maximum precision
path.digits(null);
const precisePathString = path(feature);
console.log(precisePathString); // Full precision coordinates

Multi-Geometry Handling

import { geoPath, geoMercator } from "d3-geo";

const projection = geoMercator();
const path = geoPath(projection);

// Handle different geometry types
const geometries = [
  {
    type: "Point",
    coordinates: [-74, 40.7]
  },
  {
    type: "LineString", 
    coordinates: [[-74, 40], [-73, 41]]
  },
  {
    type: "Polygon",
    coordinates: [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]
  },
  {
    type: "MultiPoint",
    coordinates: [[-74, 40], [-73, 41], [-72, 42]]
  },
  {
    type: "MultiLineString",
    coordinates: [[[-74, 40], [-73, 41]], [[-72, 42], [-71, 43]]]
  },
  {
    type: "MultiPolygon",
    coordinates: [
      [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]],
      [[[2, 2], [3, 2], [3, 3], [2, 3], [2, 2]]]
    ]
  }
];

// Path generator handles all geometry types
geometries.forEach((geometry, i) => {
  const pathString = path(geometry);
  console.log(`Geometry ${i}: ${pathString}`);
});

Feature Collection Processing

import { geoPath, geoAlbers } from "d3-geo";

const projection = geoAlbers();
const path = geoPath(projection);

const featureCollection = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      properties: { name: "State 1", value: 100 },
      geometry: { /* polygon geometry */ }
    },
    {
      type: "Feature", 
      properties: { name: "State 2", value: 200 },
      geometry: { /* polygon geometry */ }
    }
  ]
};

// Process entire feature collection
const collectionPath = path(featureCollection);

// Or process individual features
const individualPaths = featureCollection.features.map(feature => ({
  name: feature.properties.name,
  path: path(feature),
  area: path.area(feature),
  centroid: path.centroid(feature)
}));

// Create choropleth map
const colorScale = d3.scaleSequential(d3.interpolateBlues)
  .domain([0, d3.max(featureCollection.features, d => d.properties.value)]);

svg.selectAll("path")
  .data(featureCollection.features)
  .enter().append("path")
  .attr("d", path)
  .attr("fill", d => colorScale(d.properties.value))
  .attr("stroke", "white");