Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/two-n/cirque
Utilities for negotiating between circles and polygons in SVG
https://github.com/two-n/cirque
animation circle geometry transitions
Last synced: about 2 months ago
JSON representation
Utilities for negotiating between circles and polygons in SVG
- Host: GitHub
- URL: https://github.com/two-n/cirque
- Owner: two-n
- License: mit
- Created: 2017-04-01T06:00:45.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2017-04-22T01:15:44.000Z (almost 8 years ago)
- Last Synced: 2024-04-24T13:36:03.245Z (10 months ago)
- Topics: animation, circle, geometry, transitions
- Language: JavaScript
- Homepage: http://projects.two-n.com/cirque/
- Size: 243 KB
- Stars: 12
- Watchers: 3
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Cirque
Utilities for negotiating between circles and paths in SVG. See [demo](http://projects.two-n.com/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](#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](https://github.com/d3/d3-geo#geoPath). 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
```js
let render // Given a function that renders SVG paths
let path // Given a geo path generator
```### Example: geometry
```js
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
```js
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) ) })
```## Approach
- Aligns circle and path by tracing a circle using the path's commands
- Splits path commands when necessary to maintain a balance between a) mapping path commands uniformly, and b) aligning per distance unit
- Avoids [more sophisticated](http://spencermortensen.com/articles/bezier-circle/) circle approximation methods in favor of high-rate sampling## Limitations
The _chain path_ is a SVG path description of a polygonal chain (i.e. polyline, composite BΓ©zier, etc.) containing any SVG path commands except arcs, support for which 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.
## Shape morphing alternatives
- [SVG.js path morphing plugin](https://github.com/svgdotjs/svg.pathmorphing.js): simple and well done. Has some of the same approach and associated limitations
- [SVG Morpheus](http://alexk111.github.io/SVG-Morpheus/): works well and supports arbitrary SVG π
- [MorphSVG](https://greensock.com/morphSVG): proprietary but seems quite customizable and the demos are awesome## Discussion and contribution
Open an [issue](https://github.com/two-n/cirque/issues/new) or [pull request](https://github.com/two-n/cirque/compare) with either high-level use cases or practical support tickets, or contact us on [twitter](https://twitter.com/2nfo). We intend to keep this package focused on its stated mission, but advice, critique, and experiences are very welcome.