cirque

0.2.0 • Public • Published

Cirque

Utilities for negotiating between circles and paths in SVG. See demo.

Cirque

npm install --save cirque (or yarn add cirque)

Functions

# interpolatePath(a, b)

Interpolates between two SVG path description strings.

Expects a circle path (which gets sampled) and a polygonal chain path (which gets oversampled when necessary), although two circles work just by ordinary interpolation, and two chains should work in many cases as well.

# interpolatePaths(a, b)

Individually interpolates (using interpolatePath) between corresponding items in two parallel arrays of SVG path strings.

# circlePath(circle)

Converts the passed circle object to an SVG path string (i.e. a circle path consisting of two arc commands).

# geoToCircle(geometry, [path], [radius], [object])

Converts the geometry object to a circle object sharing its centroid.

Circle objects take the form: { x, y, r }

  • geometry: any GeoJSON geometry or feature (required)
  • path: geographic path generator. Defaults to bare d3.geoPath(), which assumes pre-projected geometry
  • radius: circle radius. Defaults to deriving radius from projected area
  • object: mutates passed existing object rather than creating a new one

# polygonToCircle(polygon)

Converts a polygon to a circle object sharing its centroid.

  • polygon: an array of polygon vertices (as two-element arrays) (required)
  • radius: circle radius. Defaults to computing radius from polygon area
  • object: mutates passed existing object rather than creating a new one

# avoidOverlap(objects, [margin])

Pass an array of circle objects to separate colliding circles so that no overlaps remain. Mutates objects in place. Margin (minimum gap, or maximum overlap if negative) defaults to 0. (Uses d3.forceCollide.)

# radiusScale(area, value)

Receives total area and total value as arguments, and returns a D3 scale in which the area of a circle with the given radius corresponds to a linearly-scaled value.

Examples

let render  // Given a function that renders SVG paths
let path    // Given a geo path generator

Example: geometry

import { geoToCircle, circlePath, interpolatePath } from 'cirque'
 
let geometry  // Given a GeoJSON Polygon or MultiPolygon geometry
 
const interpolator = interpolatePath(
  path(geometry),
  circlePath( geoToCircle(geometry, path) )
)
 
d3.transition().tween('shape', () => t => { render( interpolator(t) ) })

Example: features

import * as cirque from 'cirque'
 
let features  // Given an array of GeoJSON Polygon or MultiPolygon features
 
const scale = cirque.radiusScale( path.area(mergedFeatures), 7.5e9 )
const circles = features.map(feature =>
  circle.geoToCircle(feature, path, scale(feature.properties['population']))
)
 
const separatedCircles = cirque.avoidOverlap(circles)
const circlePaths = separatedCircles.map(cirque.circlePath)
const interpolator = cirque.interpolatePaths(features.map(path), circlePaths)
 
d3.transition().tween('shapes', () => t => { render( interpolator(t) ) })

Limitations

The chain path is a SVG path description of a polygonal chain (i.e. polyline, composite Bézier, etc.) containing M commands as well as absolute or relative L, C, and Z commands. Support for all path commands is planned.

The circle path is a SVG path description containing an M command followed by at least one A command (but typically two). circlePath is a utility for generating simple, compatible circle paths. Some more flexiblility in the format may come in the future, including (optionally) adhering to winding order.

Rationale

Just as a lack of color is physically considered black (though artistically often considered white), a lack of shape can in a certain sense be called a circle (or a n-sphere generally): no discrete segmentation, and no starting point any better than another.

This shapelessness is desirable for comparing values in a controlled way (say, in a bubble map) to minimize distortion and distraction.

The tools in this package amount to a method for going between precise forms such as geographic areas, and corresponding value-sized bubbles, while maintaining constancy.

Approach

  • Avoids any available more sophisticated circle approximation methods in favor of brute force sampling, and splits path commands when necessary to maintain a balance between a) mapping path commands uniformly and b) aligning per distance unit.

Discussion and contribution

Open an issue or pull request with either high-level use cases or practical support tickets, or contact us on Twitter. We do intend for this package to stay within its stated mission, but advice, critique, and experiences are welcome.

Readme

Keywords

none

Package Sidebar

Install

npm i cirque

Weekly Downloads

4

Version

0.2.0

License

MIT

Last publish

Collaborators

  • harrysolovay