Safe Haskell | Safe-Inferred |
---|---|
Language | GHC2021 |
SVG path manipulation
Synopsis
- data PathData a
- pointPath :: PathData a -> Point a
- movePath :: Additive a => Point a -> PathData a -> PathData a
- scalePath :: Multiplicative a => a -> PathData a -> PathData a
- projectPath :: Rect Double -> Rect Double -> Point Double -> PathData Double -> PathData Double
- projectPaths :: Rect Double -> Rect Double -> [PathData Double] -> [PathData Double]
- pathBoxes :: [PathData Double] -> Maybe (Rect Double)
- pathBox :: Point Double -> PathData Double -> Rect Double
- data ArcInfo a = ArcInfo {}
- data ArcPosition a = ArcPosition {}
- data ArcCentroid a = ArcCentroid {}
- arcCentroid :: (Ord a, FromInteger a, TrigField a, ExpField a) => ArcPosition a -> ArcCentroid a
- arcPosition :: (Ord a, Absolute a, TrigField a) => ArcCentroid a -> ArcPosition a
- arcBox :: ArcPosition Double -> Rect Double
- arcDerivs :: Point Double -> Double -> (Double, Double)
- ellipse :: (Direction b, Dir b ~ a, Affinity b a, TrigField a) => b -> b -> a -> a -> b
- data QuadPosition a = QuadPosition {}
- data QuadPolar a = QuadPolar {}
- quadPosition :: TrigField a => QuadPolar a -> QuadPosition a
- quadPolar :: (Eq a, TrigField a, ExpField a) => QuadPosition a -> QuadPolar a
- quadBox :: QuadPosition Double -> Rect Double
- quadBezier :: (FromInteger a, ExpField a) => QuadPosition a -> a -> Point a
- quadDerivs :: QuadPosition Double -> [Double]
- data CubicPosition a = CubicPosition {
- cposStart :: Point a
- cposEnd :: Point a
- cposControl1 :: Point a
- cposControl2 :: Point a
- data CubicPolar a = CubicPolar {
- cpolStart :: Point a
- cpolEnd :: Point a
- cpolControl1 :: Polar a
- cpolControl2 :: Polar a
- cubicPosition :: (Eq a, TrigField a, ExpField a) => CubicPolar a -> CubicPosition a
- cubicPolar :: (Eq a, ExpField a, TrigField a) => CubicPosition a -> CubicPolar a
- cubicBox :: CubicPosition Double -> Rect Double
- cubicBezier :: (FromInteger a, TrigField a) => CubicPosition a -> a -> Point a
- cubicDerivs :: CubicPosition Double -> [Double]
- singletonCubic :: CubicPosition Double -> [PathData Double]
- singletonQuad :: QuadPosition Double -> [PathData Double]
- singletonArc :: ArcPosition Double -> [PathData Double]
- singletonPie :: Point Double -> ArcPosition Double -> [PathData Double]
Svg Paths
Every element of an SVG path can be thought of as exactly two points in space, with instructions of how to draw a curve between them. From this point of view, one which this library adopts, a path chart is thus very similar to a line chart. There's just a lot more information about the style to deal with.
References:
Representation of a single SVG path data point
StartP (Point a) | Starting position |
LineP (Point a) | line (from previous position) |
CubicP (Point a) (Point a) (Point a) | cubic bezier curve |
QuadP (Point a) (Point a) | quad bezier curve |
ArcP (ArcInfo a) (Point a) |
Instances
movePath :: Additive a => Point a -> PathData a -> PathData a Source #
Move the Point part of a PathData
scalePath :: Multiplicative a => a -> PathData a -> PathData a Source #
Multiplicatively scale a PathData
projectPath :: Rect Double -> Rect Double -> Point Double -> PathData Double -> PathData Double Source #
Project a PathData from one Rect (XY plave) to a new one.
projectPaths :: Rect Double -> Rect Double -> [PathData Double] -> [PathData Double] Source #
Project a list of connected PathDatas from one Rect (XY plave) to a new one.
pathBox :: Point Double -> PathData Double -> Rect Double Source #
Bounding box for a path info, start and end Points.
Path maths
Information about an individual arc path.
Instances
Generic (ArcInfo a) Source # | |
(Ord a, Additive a, Show a) => Show (ArcInfo a) Source # | |
Eq a => Eq (ArcInfo a) Source # | |
type Rep (ArcInfo a) Source # | |
Defined in Data.Path type Rep (ArcInfo a) = D1 ('MetaData "ArcInfo" "Data.Path" "chart-svg-0.7.0.0-4dcr9v8qVDf788ykYWIDig" 'False) (C1 ('MetaCons "ArcInfo" 'PrefixI 'True) ((S1 ('MetaSel ('Just "radii") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Point a)) :*: S1 ('MetaSel ('Just "phi") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)) :*: (S1 ('MetaSel ('Just "large") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Bool) :*: S1 ('MetaSel ('Just "clockwise") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Bool)))) |
data ArcPosition a Source #
Specification of an Arc using positional referencing as per SVG standard.
Instances
data ArcCentroid a Source #
Arc specification based on centroidal interpretation.
See: https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
Instances
arcCentroid :: (Ord a, FromInteger a, TrigField a, ExpField a) => ArcPosition a -> ArcCentroid a Source #
convert from an ArcPosition spec to ArcCentroid spec.
See also this
>>>
let p = ArcPosition (Point 0 0) (Point 1 0) (ArcInfo (Point 1 0.5) (pi/4) False True)
>>>
arcCentroid p
ArcCentroid {centroid = Point 0.20952624903444356 (-0.48412291827592724), radius = Point 1.0 0.5, cphi = 0.7853981633974483, ang0 = 1.3753858999692936, angdiff = -1.823476581936975}
arcPosition :: (Ord a, Absolute a, TrigField a) => ArcCentroid a -> ArcPosition a Source #
Convert from an ArcCentroid to an ArcPosition specification.
Morally,
arcPosition . arcCentroid == id
Not isomorphic if:
- angle diff is pi and large is True
- radii are less than they should be and thus get scaled up.
arcBox :: ArcPosition Double -> Rect Double Source #
compute the bounding box for an arcBox
let p = ArcPosition (Point 0 0) (Point 1 0) (ArcInfo (Point 1 0.5) (pi/4) False True) arcBox p
arcDerivs :: Point Double -> Double -> (Double, Double) Source #
Potential arc turning points.
>>>
arcDerivs (Point 1 0.5) (pi/4)
(-0.4636476090008061,0.4636476090008062)
ellipse :: (Direction b, Dir b ~ a, Affinity b a, TrigField a) => b -> b -> a -> a -> b Source #
Ellipse formulae
>>>
ellipse zero (Point 1 2) (pi/6) pi
Point (-0.8660254037844388) (-0.4999999999999997)
Compare this "elegent" definition from stackexchange
\[\dfrac{((x-h)\cos(A)+(y-k)\sin(A))^2}{a^2}+\dfrac{((x-h) \sin(A)-(y-k) \cos(A))^2}{b^2}=1\]
with the haskell code:
c + (rotate phi |. (r * ray theta))
See also: wolfram
data QuadPosition a Source #
Quadratic bezier curve expressed in positional terms.
Instances
Quadratic bezier curve with control point expressed in polar terms normalised to the start - end line.
Instances
Generic (QuadPolar a) Source # | |
(Ord a, Additive a, Show a) => Show (QuadPolar a) Source # | |
Eq a => Eq (QuadPolar a) Source # | |
type Rep (QuadPolar a) Source # | |
Defined in Data.Path type Rep (QuadPolar a) = D1 ('MetaData "QuadPolar" "Data.Path" "chart-svg-0.7.0.0-4dcr9v8qVDf788ykYWIDig" 'False) (C1 ('MetaCons "QuadPolar" 'PrefixI 'True) (S1 ('MetaSel ('Just "qpolStart") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Point a)) :*: (S1 ('MetaSel ('Just "qpolEnd") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Point a)) :*: S1 ('MetaSel ('Just "qpolControl") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Polar a))))) |
quadPosition :: TrigField a => QuadPolar a -> QuadPosition a Source #
Convert from a polar to a positional representation of a quadratic bezier.
quadPosition . quadPolar == id quadPolar . quadPosition == id
>>>
quadPosition $ quadPolar (QuadPosition (Point 0 0) (Point 1 1) (Point 2 (-1)))
QuadPosition {qposStart = Point 0.0 0.0, qposEnd = Point 1.0 1.0, qposControl = Point 2.0 (-0.9999999999999998)}
quadPolar :: (Eq a, TrigField a, ExpField a) => QuadPosition a -> QuadPolar a Source #
Convert from a positional to a polar representation of a cubic bezier.
>>>
quadPolar (QuadPosition (Point 0 0) (Point 1 1) (Point 2 (-1)))
QuadPolar {qpolStart = Point 0.0 0.0, qpolEnd = Point 1.0 1.0, qpolControl = Polar {radial = 2.1213203435596424, azimuth = -0.7853981633974483}}
quadBox :: QuadPosition Double -> Rect Double Source #
Bounding box for a QuadPosition
>>>
quadBox (QuadPosition (Point 0 0) (Point 1 1) (Point 2 (-1)))
Rect 0.0 1.3333333333333335 (-0.33333333333333337) 1.0
quadBezier :: (FromInteger a, ExpField a) => QuadPosition a -> a -> Point a Source #
The quadratic bezier equation
>>>
quadBezier (QuadPosition (Point 0 0) (Point 1 1) (Point 2 (-1))) 0.33333333
Point 0.9999999933333332 (-0.33333333333333326)
quadDerivs :: QuadPosition Double -> [Double] Source #
QuadPosition turning points.
>>>
quadDerivs (QuadPosition (Point 0 0) (Point 1 1) (Point 2 (-1)))
[0.6666666666666666,0.3333333333333333]
data CubicPosition a Source #
Cubic bezier curve
Note that the ordering is different to the svg standard.
CubicPosition | |
|
Instances
data CubicPolar a Source #
A polar representation of a cubic bezier with control points expressed as polar and normalised to the start - end line.
CubicPolar | |
|
Instances
cubicPosition :: (Eq a, TrigField a, ExpField a) => CubicPolar a -> CubicPosition a Source #
Convert from a polar to a positional representation of a cubic bezier.
cubicPosition . cubicPolar == id cubicPolar . cubicPosition == id
>>>
cubicPosition $ cubicPolar (CubicPosition (Point 0 0) (Point 1 1) (Point 1 (-1)) (Point 0 2))
CubicPosition {cposStart = Point 0.0 0.0, cposEnd = Point 1.0 1.0, cposControl1 = Point 1.0 (-1.0), cposControl2 = Point 1.6653345369377348e-16 2.0}
cubicPolar :: (Eq a, ExpField a, TrigField a) => CubicPosition a -> CubicPolar a Source #
Convert from a positional to a polar representation of a cubic bezier.
cubicPosition . cubicPolar == id cubicPolar . cubicPosition == id
>>>
cubicPolar (CubicPosition (Point 0 0) (Point 1 1) (Point 1 (-1)) (Point 0 2))
CubicPolar {cpolStart = Point 0.0 0.0, cpolEnd = Point 1.0 1.0, cpolControl1 = Polar {radial = 1.1180339887498947, azimuth = -1.2490457723982544}, cpolControl2 = Polar {radial = 1.1180339887498947, azimuth = 1.8925468811915387}}
cubicBox :: CubicPosition Double -> Rect Double Source #
Bounding box for a CubicPosition
>>>
cubicBox (CubicPosition (Point 0 0) (Point 1 1) (Point 1 (-1)) (Point 0 2))
Rect 0.0 1.0 (-0.20710678118654752) 1.2071067811865475
cubicBezier :: (FromInteger a, TrigField a) => CubicPosition a -> a -> Point a Source #
The cubic bezier equation
>>>
cubicBezier (CubicPosition (Point 0 0) (Point 1 1) (Point 1 (-1)) (Point 0 2)) 0.8535533905932737
Point 0.6767766952966369 1.2071067811865475
cubicDerivs :: CubicPosition Double -> [Double] Source #
Turning point positions for a CubicPosition (0,1 or 2)
>>>
cubicDerivs (CubicPosition (Point 0 0) (Point 1 1) (Point 1 (-1)) (Point 0 2))
[0.8535533905932737,0.14644660940672624,0.5]
singletonCubic :: CubicPosition Double -> [PathData Double] Source #
Convert cubic position to path data.
singletonQuad :: QuadPosition Double -> [PathData Double] Source #
Convert quad position to path data.
singletonArc :: ArcPosition Double -> [PathData Double] Source #
Convert arc position to path data.
singletonPie :: Point Double -> ArcPosition Double -> [PathData Double] Source #
Convert arc position to a pie slice, with a specific center.