1.0.41 • Published 12 months ago

@irwinproject/shapley v1.0.41

Weekly downloads
-
License
ISC
Repository
-
Last release
12 months ago

Shapley

Shapley is a component library which uses an svg layer to render components as non rectangular shapes.

Installation

npm install @irwinproject/shapley

How it works.

Shapley uses an svg as a background layer which references cached path commands to clip and portray components as a custom shape. To accomplish this a lightweight svg path command parser has been implemented and made available which is useful in building animated paths or dynamic renderings in real time.

Usage

Shape Component

The shape component can be used to reference cached shapes and to draw shapes on demand.

Props
PropTypeDescription
d(optional) string | Daccepts a string of svg path commands or an instance of D
pathProps(optional) {}if d is provided this object can be used to modify the other properties used in the <path> component.
sref(optional) stringsref is used to reference a cached shape by providing the id assigned to the shape.
fill(optional) stringused to directly override the fill property in the underlying <use> component
stroke(optional) stringused to directly override the stroke property in the underlying <use> component.
strokeWidth(optional) stringused to directly override the strokeWidth property in the underlying <use> component.
useProps(optional) {}override any additional properties available in the underlying <use> component
svgProps(optional) {}override any properties in the background <svg> layer.
import { Shape } from "@irwinproject/shapley";

export const MyComponent = () => {
	return (<Shape 
	className="diamond-styles" 
	as="h4" 
	d="M 0.5,0 1,0.5 0.5,1 0,0.5z">
		Hello World!
	<Shape>);
};

Glyph

A glyph is a component that allows a sort of canvas to draw with path commands.

Currently glyphs cant be cached.

Glyphs accept all the properties a <path> component accepts however d also accepts a D instance.

Additional Props

PropTypeDescription
width(optional) stringThe width passed to the underlying svg component. If not provided it will fill its parent intrinsic width.
height(optional) stringThe height passed to the underlying svg component. If not provided it will fill its parent intrinsic height.
viewBox(optional) stringThe viewBox can be overriden however if no viewBox is provided one will be inferred based upon path commands. (this may cause clipping to strokes when inferred. D does have a setMargin method that will assist in preventing this effect.)
svgProps(optional) {}With the exception of the width, height and viewbox props accepted at the root level this object accepts all the properties a <svg> component accepts.
import { Glyph } from "@irwinproject/shapley";

export const MyGlyph = ()=>{
	return <Glyph d={D.rounded(0, [
		100,75, 0,-50, -50,-25, -50,25, 0,50, 100,50, 0,50, -50,25, -50,-25, 0,-50
	])}>
}

ShapeCache

A shape cache is a special (invisible) svg component which only contains cached shapes or paths available by reuse.

import { ShapeCache, D } from "@irwinproject/shapley";

export const MyCache = () => {
	return (<ShapeCache shapes={{
		hexagon: D.polygon(6, {rotation: 30}).toObjectBounding(),
		pentagon: D.polygon(5, {rotation: 90}).toObjectBounding(),
		diamond: D.polygon(4).toObjectBounding()
	}}>);
}

if a cached shape is going to be used as a background layer it is recommended the shape be converted to a objectBounding viewBox. (This allows the shape to scale with the bounds of the rectangle.)

import { Shape } from "@irwinproject/shapley";

export const Hexagon = () => {
	return (<Shape 
	sref="hexagon">
		Hello World
	</Shape>);
}

Shape Grids

Shape grids are simply css grids with some properties to help layout overlapping bounding recs more simply.

For a shape grid to work propely either both the grid-column-template and/or grid-row-template will need to be set. either by utilizing the cellColumns or the cellRows property. (the templates can also be applied directly using css).

The cellSize property is necessary as well. the first value being the number of columns a cell spans while the second is the number of rows a cell spans. (these can be applied directly with css using the grid-column-end and grid-row-end).

I provide a few layout functions that simplify laying out grids with regular polygons however custom layout functions can be made as well.

import { ShapleyGrid, HexagonLayout } from "@irwinproject/shapley";
const GridComponent = () => {
	return (<ShapleyGrid cellColumns="repeat(6, 1fr 2fr) 1fr" cellSize={[3,2]} layoutFN={HexagonLayout(6, 'hexagon')}>
		<ShapleyGridCell>
			{/*...*/}
		</ShapleyGridCell>
		{/* If a layout function is not provided the row, column and shape reference (sref) property can be set directly on the grid cell*/}
		<ShapleyGridCell row={2} column={3} sref="hexagon"></ShapleyGridCell>
	</ShapleyGrid>)
}

Layout functions

Layout functions are a way to describe a cell position based upon the index. This allows the cells bounding rects to overlap without statically providing cell positioning in css.

Each cell uses a shape to clip its bounding rect to ensure mouse events are triggered on the correct component.

type LayoutFN = (index: number) => ({
	row: number,
	column: number,
	sref?: string
})

Any functions complying to this pattern can be used to layout grid cells. the index value provided is the sequential index of the component being iterated.

Warning: The Shapley grid only inject these properties into children ShapleyGridCell.

Styling

The shape component can be styled like most other html elements with a few exceptions

  • Do not use css borders CSS borders are always rectangular Instead utilize svg's stroke properties.
  • Do not use Drop-shadow Currently using filter and backdrop-filter on a shapes parent object are the best method to add shadows to shapes. it may be possible to make custom effects such as <feDropShadow> that can be applied directly to a shape. I will explore this when time allows.

The recommended method to style a shape is via css or css-in-js.

CSS Variables.

Variable Nameexample valueDescription
--shapley-aspect-ratio1/1The shapley aspect ratio set thes aspect ratio of any shapley components that inherit this value.
--shapley-clipurl('#<id to clip path based on shape path>)Along with shape commands a clip path is also created for each shape which can be used separate from the shape component. (clip paths generated by shapley will use the following naming convention. #<shape id>-clip)
--shapley-filterblur(8px)This is an experimental feature I was hoping would provide a convenient method for creating a shadow or blur effect. That being said I may need to revisit this and generate svg based shadows and blurs that will work as expected
--shapley-bg-color<Any CSS supported color >The shapley bg color is applied to the components use tag's fill property. This can be a convenient method to add an overlay or set. (this variable was added prior to the decision to clip all shapes, it is recommended to utilize css background properties prior to using the fill method.)
--shapley-stroke-color<Any CSS supported color >The color to be used to stroke the shape.
--shapley-stroke-width0.1The width of the svg stroke.
--shapley-stroke-linejoinroundThe line join property of the path or use tag
--shapley-stroke-linecaproundThe line cap property of the path or use tag
--grid-column1The column start index for a ShapeGridCell.
--grid-row1The row start index for a ShapeGridCell.
--shape-height2The number of Grid cells the shape occupies vertically.
--shape-width3The number of Grid cells the shape occupies horizontally.

### Classes

Classnamedescription
.shapley-shapeapplies the aspect ratio clip path and display properties of the root component and applies styled to the svg background layer
.shapley-shape-bgThis class is used to identify a the svg background layer however css rules are only applied if its the immediate child of a .shapley-shape
.shapley-cacheThis class is used to identify a shapley cache. by default this hides the cache visibly and removes any intrinsic dimensions. It also makes the cache a fixed component so it does not effect the layout of sibling components.
.shapley-gridThe class used to identify a Shape Grid
.shapley-grid-cellThe class used to identify a Shape Grid Cell

D

D is an attempt to make svg path commands a bit more useful in javascript.

D acts as a sort of lazy buffer which combines mutation operations to be performed the next time the path commands are requested for render.

D and all of its subsequent classes are convertable to a string which will result in a valid path command string.

for D to work as it should its backing store holds a IterableIterator (generator) instead of an array of points. this allows for multiple source of truth formats to be applicable. The simplest way to explain this is the source of truth can be anything your providing the instructions on how to traverse that source of truth.

This has two effects. generators can be combined to essencially enqueue modifications to occur in the next render cycle. Additionally, Path commands can be generated programmatically, via static string, or even with arbitrary types such as a flat array of numbers.

Some limitations include:

  • Number of points within the buffer is unknown
  • Points can only be iterated in order if reference to separate points is desired two iterations will be necessary to index the points.

I will be releasing more detailed documentation soon.

constructor

Typically a static method would be used to create a D instance. the constructor accepts multiple types.

arg: string | number[] | Command[] | ()=>Generator<Command>

  • the initializer type.
  • If a string is provided to first argument it will be parsed as a path command. The source of truth will be the string and each time its iterated.
  • If a number array is provided the array will be iterated over by two concluding with a z command to close the shape.
  • If a Command Generator is provided you have direct control over the PathCommand instances. (Currently these classes are experimental I will release more documentation soon.).

margin: number

This value will be applied to each side of the view box.

properties

PropertyTypeDescription
firstPosition(optional) PointThis property is used during the render cycle to track the point a z tag will close to. this value will only be populated during a the render cycle.
currentPosition?:(optional) PointThis property acts as a cursor tracking the current position the iterator is at during the render cycle. This value will only be populated during the render cycle similar to the firstPosition property.
boundsminX: number, minY: number, width: number, height: number, maxX:number, maxY: numberEach time D is stringified it will generate an intrinsic bounds based on the contained points. As such the instance must be converted to a string prior to this being called for its values to be valid.
marginnumber = 0Due to the D property not being knowledgable of any specific styling properties this allows a margin to be applied to each side of the path.
viewBoxstringThis is a getter and cannot be overriden. This value reflects the svg viewBox specific to this path.
aspectRatiostringThis is a getter however has the ability to be overriden. This becomes important when working with a non linear unit system such as objectBoundingUnits. while the maxX and Y are both 1 this does not mean the shape is square in such circumstances. This property is used to maintain the aspect ratio despite if the path is using non linear units.
isObjectBoundingbooleanThis property can be used to check if the values in the path comply with an object bounding path.
setMarginthisapplies a margin value.

methods

PropertyReturnDescription
getBoundsminX: number, minY: number, width: number, height: number, maxX:number, maxY: numberThis method can be used to get the bounds even if the path has not yet been measured.
eachGeneratorAn iterator that as it iterates updates the cursor, bounds and subsequently the viewbox.
translate(x:number, y:number)thistranslates points. This becomes a bit complicated because absolute and relative positions are translated differently. As such this translates all absolutely positioned points and if the first command is a m command it to will be translated.
scale(x:number, y:number)thisscales points based on an x and y value.
toObjectBounding()thisConverts a non object bounding path to an object bounding units.
cached(){d: string, aspectRatio: string, objectBounding: boolean}A cached item is the passing of the minimum amount of information to a simple json object which can be used to regenerate the instance on another platform.
toString()stringConverts the instance to a path command string

Static methods

D has a range of static methods to assist in initializing and creating various shapes. | Property | Return | Description | |:--------:|:----:|:-----------:| | parse(d: string) | Generator<Command> | parse a path command string to an instance of D. | | fromLines(d: number[]) | Generator<Command> | treats the array as a 2d vertex list of points. | | polygon(sides: number, options?: {}) | D | Generate a regular polygon of the provided number of sides. this method supportes decimal values in the side to assist with animation. | | polygon.options.radius | number = 1 | The circumradius of the polygon | | polygon.options.rotation | number = 0 | Degrees the object should be rotated by. | | center | x:number, y: number = 0,0 | The center point of the polygon. | | cornerRadius | number = 0 | The distance from the polygon's points at which rounding should begin. | | connectAll | boolean = false | Connecting all the points just creates an interesting effect so I figured why not. | | shape(cornerRadius: number, points: ()=>Generator(x: number, y: number) | number[]) | D | Creates a shape from an iterator of points or an Array. | | rounded(cornerRadius: number, d: readonly number[]) | D | Iterates of a vertex list and rounds each corner by the provided amount. | | fromCached(cache: DCacheItem) | D | recreate a D instance from a cache object. |

1.0.41

12 months ago

1.0.4

12 months ago

1.0.36

12 months ago

1.0.35

12 months ago

1.0.34

12 months ago

1.0.33

12 months ago

1.0.32

1 year ago

1.0.31

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.0

1 year ago