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.
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;
}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");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();
});
}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);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`);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 coordinatesimport { 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}`);
});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");