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

shapes.mddocs/

Geometric Shapes

Generation of geometric shapes like circles and graticules for cartographic applications and map overlays. These functions create GeoJSON geometries that can be projected and rendered as part of map visualizations.

Capabilities

Circle Generation

Creates GeoJSON polygon approximating a circle on the sphere.

/**
 * Creates a circle generator
 * @returns Circle generator instance
 */
function geoCircle(): Circle;

interface Circle {
  /**
   * Generates a GeoJSON polygon approximating a circle
   * @returns GeoJSON Polygon representing the circle
   */
  (): GeoJSON.Polygon;
  
  /**
   * Sets or gets the circle's center point
   * @param center - Center as [longitude, latitude] in degrees (default [0, 0])
   * @returns This circle generator or current center
   */
  center(center?: [number, number]): this | [number, number];
  
  /**
   * Sets or gets the circle's radius
   * @param radius - Radius in degrees (default 90)
   * @returns This circle generator or current radius
   */
  radius(radius?: number): this | number;
  
  /**
   * Sets or gets the circle's precision
   * @param precision - Angular precision in degrees (default 6)
   * @returns This circle generator or current precision
   */
  precision(precision?: number): this | number;
}

Usage Examples:

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

// Create a basic circle
const circle = geoCircle();
const circleGeometry = circle(); // Default: center at [0,0], radius 90°

// Configure circle properties
const customCircle = geoCircle()
  .center([-74, 40.7]) // New York
  .radius(10);         // 10-degree radius

const smallCircle = customCircle();

// Create circles for city boundaries
const cities = [
  { name: "New York", coords: [-74.006, 40.7128], radius: 5 },
  { name: "London", coords: [-0.1278, 51.5074], radius: 3 },
  { name: "Tokyo", coords: [139.6917, 35.6895], radius: 4 }
];

const cityCircles = cities.map(city => ({
  ...city,
  geometry: geoCircle()
    .center(city.coords)
    .radius(city.radius)()
}));

// Render circles on map
const projection = geoOrthographic();
const path = geoPath(projection);

svg.selectAll(".city-circle")
  .data(cityCircles)
  .enter().append("path")
  .attr("class", "city-circle")
  .attr("d", d => path(d.geometry))
  .attr("fill", "rgba(255, 0, 0, 0.3)")
  .attr("stroke", "red");

High-Precision Circles

import { geoCircle } from "d3-geo";

// Create high-precision circle for detailed visualization
const preciseCircle = geoCircle()
  .center([0, 0])
  .radius(30)
  .precision(1); // 1-degree precision for smoother curves

// Create low-precision circle for performance
const roughCircle = geoCircle()
  .center([0, 0])
  .radius(30)
  .precision(15); // 15-degree precision for fewer points

console.log("Precise circle points:", preciseCircle().coordinates[0].length);
console.log("Rough circle points:", roughCircle().coordinates[0].length);

Interactive Circles

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

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

// Create interactive circle that follows mouse
function createInteractiveCircle(svg) {
  const circleElement = svg.append("path")
    .attr("class", "interactive-circle")
    .attr("fill", "rgba(0, 100, 255, 0.2)")
    .attr("stroke", "blue");
  
  svg.on("mousemove", function(event) {
    const [x, y] = d3.pointer(event);
    const coords = projection.invert([x, y]);
    
    if (coords) {
      const circleGeometry = circle
        .center(coords)
        .radius(5)();
      
      circleElement.attr("d", path(circleGeometry));
    }
  });
}

Graticule Generation

Creates spherical coordinate grid lines (meridians and parallels) for map overlays.

/**
 * Creates a graticule generator
 * @returns Graticule generator instance
 */
function geoGraticule(): Graticule;

/**
 * Default graticule with 10-degree spacing
 */
const geoGraticule10: GeoJSON.MultiLineString;

interface Graticule {
  /**
   * Generates a GeoJSON MultiLineString representing the graticule
   * @returns GeoJSON MultiLineString with meridians and parallels
   */
  (): GeoJSON.MultiLineString;
  
  /**
   * Generates an array of individual GeoJSON LineStrings
   * @returns Array of GeoJSON LineString features for each grid line
   */
  lines(): GeoJSON.LineString[];
  
  /**
   * Generates the graticule outline as a polygon
   * @returns GeoJSON Polygon representing the graticule boundary
   */
  outline(): GeoJSON.Polygon;
  
  /**
   * Sets or gets the graticule extent (both major and minor)
   * @param extent - Extent as [[west, south], [east, north]] (default [[-180, -90], [180, 90]])
   * @returns This graticule generator or current extent
   */
  extent(extent?: [[number, number], [number, number]]): this | [[number, number], [number, number]];
  
  /**
   * Sets or gets the major lines extent
   * @param extent - Major extent as [[west, south], [east, north]] (default [[-180, -90], [180, 90]])
   * @returns This graticule generator or current major extent
   */
  extentMajor(extent?: [[number, number], [number, number]]): this | [[number, number], [number, number]];
  
  /**
   * Sets or gets the minor lines extent
   * @param extent - Minor extent as [[west, south], [east, north]] (default [[-180, -90], [180, 90]])
   * @returns This graticule generator or current minor extent
   */
  extentMinor(extent?: [[number, number], [number, number]]): this | [[number, number], [number, number]];
  
  /**
   * Sets or gets the step interval (both major and minor)
   * @param step - Step as [longitude_step, latitude_step] (default [10, 10])
   * @returns This graticule generator or current step
   */
  step(step?: [number, number]): this | [number, number];
  
  /**
   * Sets or gets the major lines step interval
   * @param step - Major step as [longitude_step, latitude_step] (default [90, 360])
   * @returns This graticule generator or current major step
   */
  stepMajor(step?: [number, number]): this | [number, number];
  
  /**
   * Sets or gets the minor lines step interval
   * @param step - Minor step as [longitude_step, latitude_step] (default [10, 10])
   * @returns This graticule generator or current minor step
   */
  stepMinor(step?: [number, number]): this | [number, number];
  
  /**
   * Sets or gets the graticule precision
   * @param precision - Precision in degrees (default 2.5)
   * @returns This graticule generator or current precision
   */
  precision(precision?: number): this | number;
}

Usage Examples:

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

// Use default 10-degree graticule
const projection = geoMercator();
const path = geoPath(projection);

svg.append("path")
  .datum(geoGraticule10)
  .attr("class", "graticule")
  .attr("d", path)
  .attr("fill", "none")
  .attr("stroke", "#ccc")
  .attr("stroke-width", 0.5);

// Create custom graticule
const customGraticule = geoGraticule()
  .step([15, 15])        // 15-degree grid
  .extent([[-180, -60], [180, 60]]); // Exclude polar regions

const gridLines = customGraticule();

svg.append("path")
  .datum(gridLines)
  .attr("class", "custom-graticule")
  .attr("d", path)
  .attr("fill", "none")
  .attr("stroke", "blue")
  .attr("stroke-width", 0.3);

Fine-Grained Graticule Control

import { geoGraticule } from "d3-geo";

// Create graticule with different major/minor spacing
const detailedGraticule = geoGraticule()
  .stepMajor([30, 30])    // Major lines every 30 degrees
  .stepMinor([5, 5])      // Minor lines every 5 degrees
  .precision(1);          // High precision

// Regional graticule for Europe
const europeGraticule = geoGraticule()
  .extent([[-15, 35], [40, 70]])  // Europe bounds
  .step([5, 5])                   // 5-degree spacing
  .precision(2);

// Render different line types
const graticuleData = europeGraticule();
const individualLines = europeGraticule.lines();

// Render major and minor lines with different styles
svg.selectAll(".major-line")
  .data(individualLines.filter((d, i) => i % 6 === 0)) // Every 6th line as major
  .enter().append("path")
  .attr("class", "major-line")
  .attr("d", path)
  .attr("stroke", "#666")
  .attr("stroke-width", 1);

svg.selectAll(".minor-line")
  .data(individualLines.filter((d, i) => i % 6 !== 0)) // Other lines as minor
  .enter().append("path")
  .attr("class", "minor-line")
  .attr("d", path)
  .attr("stroke", "#ccc")
  .attr("stroke-width", 0.5);

Graticule Outline

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

const projection = geoOrthographic();
const path = geoPath(projection);
const graticule = geoGraticule();

// Add sphere outline
svg.append("path")
  .datum(graticule.outline())
  .attr("class", "sphere-outline")
  .attr("d", path)
  .attr("fill", "lightblue")
  .attr("stroke", "steelblue")
  .attr("stroke-width", 2);

// Add graticule lines
svg.append("path")
  .datum(graticule())
  .attr("class", "graticule")
  .attr("d", path)
  .attr("fill", "none")
  .attr("stroke", "rgba(255, 255, 255, 0.5)")
  .attr("stroke-width", 0.5);

Polar Projection Graticule

import { geoGraticule, geoAzimuthalEqualArea } from "d3-geo";

// Create polar-focused graticule
const polarGraticule = geoGraticule()
  .extent([[-180, 60], [180, 90]])  // Arctic region
  .step([15, 5])                    // Dense latitude lines, sparse longitude
  .precision(1);

// Polar projection
const polarProjection = geoAzimuthalEqualArea()
  .rotate([0, -90])  // North pole at center
  .scale(250);

const path = geoPath(polarProjection);

// Render polar grid
svg.append("path")
  .datum(polarGraticule())
  .attr("d", path)
  .attr("fill", "none")
  .attr("stroke", "#333")
  .attr("stroke-width", 0.5);

Dynamic Graticule

import { geoGraticule } from "d3-geo";

// Create zoom-responsive graticule
function createAdaptiveGraticule(zoomLevel) {
  const step = Math.max(1, 10 / zoomLevel); // Denser grid at higher zoom
  
  return geoGraticule()
    .step([step, step])
    .precision(Math.max(0.5, 2.5 / zoomLevel));
}

// Update graticule on zoom
function updateGraticule(zoomLevel) {
  const adaptiveGraticule = createAdaptiveGraticule(zoomLevel);
  
  svg.select(".adaptive-graticule")
    .datum(adaptiveGraticule())
    .attr("d", path);
}

// Zoom behavior
const zoom = d3.zoom()
  .scaleExtent([0.5, 8])
  .on("zoom", function(event) {
    const { transform } = event;
    updateGraticule(transform.k);
  });

svg.call(zoom);