{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}

{-|
Module      : Graphics.Vega.VegaLite.Geometry
Copyright   : (c) Douglas Burke, 2018-2020
License     : BSD3

Maintainer  : dburke.gw@gmail.com
Stability   : unstable
Portability : CPP, OverloadedStrings

Geometric shapes and projections.

-}

module Graphics.Vega.VegaLite.Geometry
       ( geometry
       , geoFeatureCollection
       , geometryCollection
       , Geometry(..)

       , sphere
       , graticule
       , GraticuleProperty(..)

       , projection
       , ProjectionProperty(..)
       , Projection(..)
       , ClipRect(..)

       -- not for external export
       , projectionProperty

       ) where

import qualified Data.Aeson as A
import qualified Data.Text as T

import Control.Arrow (second)
import Data.Aeson ((.=), object, toJSON)

#if !(MIN_VERSION_base(4, 12, 0))
import Data.Monoid ((<>))
#endif


import Graphics.Vega.VegaLite.Data
  ( DataValue
  , dataValueSpec
  )
import Graphics.Vega.VegaLite.Foundation (fromT)
import Graphics.Vega.VegaLite.Specification
  ( VLProperty(VLData, VLProjection)
  , VLSpec
  , LabelledSpec
  , PropertySpec
  )
import Graphics.Vega.VegaLite.Input
  ( Data
  )


type_ :: T.Text -> LabelledSpec
type_ :: Text -> LabelledSpec
type_ Text
t = Text
"type" Text -> Text -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
t


{-|

Specifies a list of geo features to be used in a geoShape specification.
Each feature object in this collection can be created with the 'geometry'
function.

@
'geoFeatureCollection'
    [ 'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( -3, 52 ), ( 4, 52 ), ( -3, 59 ) ] ])
        [ ( "myRegionName", 'Graphics.Vega.VegaLite.Str' "Northern region" ) ]
    , 'geometry' ('GeoPolygon' [ [ ( -3, 52 ), ( 4, 52 ), ( 4, 45 ), ( -3, 52 ) ] ])
        [ ( "myRegionName", 'Graphics.Vega.VegaLite.Str' "Southern region" ) ]
    ]
@
-}
geoFeatureCollection :: [VLSpec] -> VLSpec
geoFeatureCollection :: [VLSpec] -> VLSpec
geoFeatureCollection [VLSpec]
geoms =
  [LabelledSpec] -> VLSpec
object [ Text -> LabelledSpec
type_ Text
"FeatureCollection"
         , Text
"features" Text -> [VLSpec] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.=  [VLSpec]
geoms
         ]


{-|

Specifies a list of geometry objects to be used in a geoShape specification.
Each geometry object in this collection can be created with the 'geometry'
function.

@
'geometryCollection'
    [ 'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []
    , 'geometry' ('GeoPoint' -3.5 55.5) []
    ]
@
-}
geometryCollection :: [VLSpec] -> VLSpec
geometryCollection :: [VLSpec] -> VLSpec
geometryCollection [VLSpec]
geoms =
  [LabelledSpec] -> VLSpec
object [ Text -> LabelledSpec
type_ Text
"GeometryCollection"
         , Text
"geometries" Text -> [VLSpec] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [VLSpec]
geoms
         ]


{-|

Types of geographic map projection. These are based on a subset of those provided
by the <https://github.com/d3/d3-geo d3-geo library>. For details of available
projections see the
<https://vega.github.io/vega-lite/docs/projection.html#projection-types Vega-Lite documentation>.
-}

-- based on schema 3.3.0 #/definitions/ProjectionType

data Projection
    = Albers
      -- ^ An Albers equal-area conic map projection.
    | AlbersUsa
      -- ^ An Albers USA map projection that combines continental USA with
      --   Alaska and Hawaii. Unlike other projection types, this remains
      --   unaffected by 'PrRotate'.
    | AzimuthalEqualArea
      -- ^ An azimuthal equal area map projection.
    | AzimuthalEquidistant
      -- ^ An azimuthal equidistant map projection.
    | ConicConformal
      -- ^ A conformal conic map projection.
    | ConicEqualArea
      -- ^ An equal area conic map projection.
    | ConicEquidistant
      -- ^ An equidistant conic map projection.
    | Custom T.Text
      -- ^ Specify the name of the custom D3 prohection to use. See the
      --   <https://vega.github.io/vega/docs/projections/#register Vega API>
      --   for more information.
      --
      --   An example: @Custom "winkle3"@
    | EqualEarth
      -- ^ An <https://github.com/d3/d3-geo#equal-earth Equal Earth map projection>
      --   that provides a reasonable shape approximation while retaining relative areas.
      --
      --   @since 0.5.0.0
    | Equirectangular
      -- ^ An equirectangular map projection that maps longitude to x and latitude to y.
      --   While showing less area distortion towards the poles than the default 'Mercator'
      --   projection, it is neither equal-area nor conformal.
    | Gnomonic
      -- ^ A gnomonic map projection.
    | Identity
      -- ^ The identiy projection. This can be combined with 'PrReflectX' and
      --   'PrReflectY' in the list of projection properties.
      --
      --   @since 0.4.0.0
    | Mercator
      -- ^ A Mercator map projection. This is the default projection of longitude, latitude
      --   values if no projection is set explicitly. It preserves shape (local angle) and
      --   lines of equal angular bearing remain parallel straight lines. The area is
      --   /significantly/ enlarged towards the poles.
    | NaturalEarth1
      -- ^ The <https://github.com/d3/d3-geo#geoNaturalEarth1 Natural Earth projection>
      --   is neither conformal nor equal-area, but is designed to be \"appealing to the
      --   eye\" for small-scale maps of the whole world.
      --
      --   @since 0.5.0.0
    | Orthographic
      -- ^ An orthographic map projection.
    | Stereographic
      -- ^ A stereographic map projection.
    | TransverseMercator
      -- ^ A transverse Mercator map projection.


projectionLabel :: Projection -> T.Text
projectionLabel :: Projection -> Text
projectionLabel Projection
Albers = Text
"albers"
projectionLabel Projection
AlbersUsa = Text
"albersUsa"
projectionLabel Projection
AzimuthalEqualArea = Text
"azimuthalEqualArea"
projectionLabel Projection
AzimuthalEquidistant = Text
"azimuthalEquidistant"
projectionLabel Projection
ConicConformal = Text
"conicConformal"
projectionLabel Projection
ConicEqualArea = Text
"conicEqualarea"
projectionLabel Projection
ConicEquidistant = Text
"conicEquidistant"
projectionLabel (Custom Text
pName) = Text
pName
projectionLabel Projection
EqualEarth = Text
"equalEarth"
projectionLabel Projection
Equirectangular = Text
"equirectangular"
projectionLabel Projection
Gnomonic = Text
"gnomonic"
projectionLabel Projection
Identity = Text
"identity"
projectionLabel Projection
Mercator = Text
"mercator"
projectionLabel Projection
NaturalEarth1 = Text
"naturalEarth1"
projectionLabel Projection
Orthographic = Text
"orthographic"
projectionLabel Projection
Stereographic = Text
"stereographic"
projectionLabel Projection
TransverseMercator = Text
"transverseMercator"


-- | Specifies a clipping rectangle for defining
--   the clip extent of a map projection.

data ClipRect
    = NoClip
      -- ^ No clipping it to be applied.
    | LTRB Double Double Double Double
      -- ^ The left, top, right, and bottom extents, in pixels,
      --   of a rectangular clip.


{-|

Properties for customising a geospatial projection that converts longitude,latitude
pairs into planar @(x,y)@ coordinate pairs for rendering and query. For details see the
<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.

This type has been changed in the @0.4.0.0@ release so that all constructors
start with @Pr@ rather than @P@ (and so provide some differentiation to the
'Graphics.Vega.VegaLite.PositionChannel' constructors).

-}

-- based on schema 3.3.0 #/definitions/Projection

data ProjectionProperty
    = PrType Projection
      -- ^ The type of the map projection.
    | PrClipAngle (Maybe Double)
      -- ^ The clipping circle angle in degrees. A value of @Nothing@ will switch to
      --   antimeridian cutting rather than small-circle clipping.
    | PrClipExtent ClipRect
      -- ^ Projection’s viewport clip extent to the specified bounds in pixels.
    | PrCenter Double Double
      -- ^ Projection’s center as longitude and latitude in degrees.
    | PrScale Double
      -- ^ The projection's zoom scale, which if set, overrides automatic scaling of a
      --   geo feature to fit within the viewing area.
      --
      --   @since 0.4.0.0
    | PrTranslate Double Double
      -- ^ A projection’s panning translation, which if set, overrides automatic positioning
      --   of a geo feature to fit within the viewing area
      --
      --   Note that the prefix is @Pr@ and not @P@, to match the Elm API.
      --
      --   @since 0.4.0.0
    | PrRotate Double Double Double
      -- ^ A projection’s three-axis rotation angle. The order is @lambda@ @phi@ @gamma@,
      --   and specifies the rotation angles in degrees about each spherical axis.
    | PrPrecision Double
      -- ^ Threshold for the projection’s adaptive resampling in pixels, and corresponds to the
      --   Douglas–Peucker distance. If precision is not specified, the projection’s current
      --   resampling precision of 0.707 is used.
      --
      --   Version 3.3.0 of the Vega-Lite spec claims this should be output as a string,
      --   but it is written out as a number since the
      --   [spec is in error](https://github.com/vega/vega-lite/issues/5190).
    | PrReflectX Bool
      -- ^ Reflect the x-coordinates after performing an identity projection. This
      --   creates a left-right mirror image of the geoshape marks when subject to an
      --   identity projection with 'Identity'.
      --
      -- @since 0.4.0.0
    | PrReflectY Bool
      -- ^ Reflect the y-coordinates after performing an identity projection. This
      --   creates a left-right mirror image of the geoshape marks when subject to an
      --   identity projection with 'Identity'.
      --
      -- @since 0.4.0.0
    | PrCoefficient Double
      -- ^ The @Hammer@ map projection coefficient.
    | PrDistance Double
      -- ^ The @Satellite@ map projection distance.
    | PrFraction Double
      -- ^ The @Bottomley@ map projection fraction.
    | PrLobes Int
      -- ^ Number of lobes in lobed map projections such as the @Berghaus star@.
    | PrParallel Double
      -- ^ Parallel for map projections such as the @Armadillo@.
    | PrRadius Double
      -- ^ Radius value for map projections such as the @Gingery@.
    | PrRatio Double
      -- ^ Ratio value for map projections such as the @Hill@.
    | PrSpacing Double
      -- ^ Spacing value for map projections such as the @Lagrange@.
    | PrTilt Double
      -- ^ @Satellite@ map projection tilt.


projectionProperty :: ProjectionProperty -> LabelledSpec
projectionProperty :: ProjectionProperty -> LabelledSpec
projectionProperty (PrType Projection
proj) = Text
"type" Text -> Text -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Projection -> Text
projectionLabel Projection
proj
projectionProperty (PrClipAngle Maybe Double
numOrNull) = Text
"clipAngle" Text -> VLSpec -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= VLSpec -> (Double -> VLSpec) -> Maybe Double -> VLSpec
forall b a. b -> (a -> b) -> Maybe a -> b
maybe VLSpec
A.Null Double -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON Maybe Double
numOrNull
projectionProperty (PrClipExtent ClipRect
rClip) =
  (Text
"clipExtent", case ClipRect
rClip of
    ClipRect
NoClip -> VLSpec
A.Null
    LTRB Double
l Double
t Double
r Double
b -> [VLSpec] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON ((Double -> VLSpec) -> [Double] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map Double -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Double
l, Double
t, Double
r, Double
b])
  )
projectionProperty (PrCenter Double
lon Double
lat) = Text
"center" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lon, Double
lat]
projectionProperty (PrScale Double
sc) = Text
"scale" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
sc
projectionProperty (PrTranslate Double
tx Double
ty) = Text
"translate" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
tx, Double
ty]
projectionProperty (PrRotate Double
lambda Double
phi Double
gamma) = Text
"rotate" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lambda, Double
phi, Double
gamma]
projectionProperty (PrPrecision Double
pr) = Text
"precision" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
pr  -- the 3.3.0 spec says this is a string, but that's wrong,  See https://github.com/vega/vega-lite/issues/5190
projectionProperty (PrReflectX Bool
b) = Text
"reflectX" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
b
projectionProperty (PrReflectY Bool
b) = Text
"reflectY" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
b
projectionProperty (PrCoefficient Double
x) = Text
"coefficient" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrDistance Double
x) = Text
"distance" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrFraction Double
x) = Text
"fraction" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrLobes Int
n) = Text
"lobes" Text -> Int -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Int
n
projectionProperty (PrParallel Double
x) = Text
"parallel" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrRadius Double
x) = Text
"radius" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrRatio Double
x) = Text
"ratio" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrSpacing Double
x) = Text
"spacing" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrTilt Double
x) = Text
"tilt" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x


{-|

Sets the cartographic projection used for geospatial coordinates. A projection
defines the mapping from @(longitude,latitude)@ to an @(x,y)@ plane used for rendering.
This is useful when using the 'Graphics.Vega.VegaLite.Geoshape' mark. For further details see the
<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.

@
'projection' [ 'PrType' 'Orthographic', 'PrRotate' (-40) 0 0 ]
@
-}
projection :: [ProjectionProperty] -> PropertySpec
projection :: [ProjectionProperty] -> PropertySpec
projection [ProjectionProperty]
pProps = (VLProperty
VLProjection, [LabelledSpec] -> VLSpec
object ((ProjectionProperty -> LabelledSpec)
-> [ProjectionProperty] -> [LabelledSpec]
forall a b. (a -> b) -> [a] -> [b]
map ProjectionProperty -> LabelledSpec
projectionProperty [ProjectionProperty]
pProps))


{-|

Specifies the type and content of geometry specifications for programatically
creating GeoShapes. These can be mapped to the
<https://tools.ietf.org/html/rfc7946#section-3.1 GeoJson geometry object types>
where the pluralised type names refer to their @Multi@ prefixed equivalent in the
GeoJSON specification.
-}
data Geometry
    = GeoPoint Double Double
    -- ^ The GeoJson geometry @point@ type.
    | GeoPoints [(Double, Double)]
    -- ^ The GeoJson geometry @multi-point@ type.
    | GeoLine [(Double, Double)]
    -- ^ The GeoJson geometry @line@ type.
    | GeoLines [[(Double, Double)]]
    -- ^ The GeoJson geometry @multi-line@ type.
    | GeoPolygon [[(Double, Double)]]
    -- ^ The GeoJson geometry @polygon@ type.
    | GeoPolygons [[[(Double, Double)]]]
    -- ^ The GeoJson geometry @multi-polygon@ type.


{-|

Specifies a geometric object to be used in a geoShape specification. The first
parameter is the geometric type, the second an optional list of properties to be
associated with the object.

@
'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []
@
-}
geometry :: Geometry -> [(T.Text, DataValue)] -> VLSpec
geometry :: Geometry -> [(Text, DataValue)] -> VLSpec
geometry Geometry
gType [(Text, DataValue)]
properties =
  [LabelledSpec] -> VLSpec
object ([ (Text
"type", Text -> VLSpec
fromT Text
"Feature")
          , (Text
"geometry", Geometry -> VLSpec
geometryTypeSpec Geometry
gType) ]
          [LabelledSpec] -> [LabelledSpec] -> [LabelledSpec]
forall a. Semigroup a => a -> a -> a
<> if [(Text, DataValue)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Text, DataValue)]
properties
             then []
             else [(Text
"properties",
                    [LabelledSpec] -> VLSpec
object (((Text, DataValue) -> LabelledSpec)
-> [(Text, DataValue)] -> [LabelledSpec]
forall a b. (a -> b) -> [a] -> [b]
map ((DataValue -> VLSpec) -> (Text, DataValue) -> LabelledSpec
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second DataValue -> VLSpec
dataValueSpec) [(Text, DataValue)]
properties))]
         )


geometryTypeSpec :: Geometry -> VLSpec
geometryTypeSpec :: Geometry -> VLSpec
geometryTypeSpec Geometry
gType =
  let toCoords :: [(Double, Double)] -> VLSpec
      toCoords :: [(Double, Double)] -> VLSpec
toCoords = [(Double, Double)] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON -- rely on Aeson converting a pair to a 2-element list

      toCoordList :: [[(Double, Double)]] -> VLSpec
      toCoordList :: [[(Double, Double)]] -> VLSpec
toCoordList = [VLSpec] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON ([VLSpec] -> VLSpec)
-> ([[(Double, Double)]] -> [VLSpec])
-> [[(Double, Double)]]
-> VLSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([(Double, Double)] -> VLSpec) -> [[(Double, Double)]] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map [(Double, Double)] -> VLSpec
toCoords  -- this is just toJSON isn't it?

      -- can we replace this infinite tower of toJSON calls with one toJSON call?
      (VLSpec
ptype, VLSpec
cs) = case Geometry
gType of
        GeoPoint Double
x Double
y -> (VLSpec
"Point", [Double] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Double
x, Double
y])
        GeoPoints [(Double, Double)]
coords -> (VLSpec
"MultiPoint", [(Double, Double)] -> VLSpec
toCoords [(Double, Double)]
coords)
        GeoLine [(Double, Double)]
coords -> (VLSpec
"LineString", [(Double, Double)] -> VLSpec
toCoords [(Double, Double)]
coords)
        GeoLines [[(Double, Double)]]
coords -> (VLSpec
"MultiLineString", [[(Double, Double)]] -> VLSpec
toCoordList [[(Double, Double)]]
coords)
        GeoPolygon [[(Double, Double)]]
coords -> (VLSpec
"Polygon", [[(Double, Double)]] -> VLSpec
toCoordList [[(Double, Double)]]
coords)
        GeoPolygons [[[(Double, Double)]]]
ccoords -> (VLSpec
"MultiPolygon", [VLSpec] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON (([[(Double, Double)]] -> VLSpec)
-> [[[(Double, Double)]]] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map [[(Double, Double)]] -> VLSpec
toCoordList [[[(Double, Double)]]]
ccoords))

  in [LabelledSpec] -> VLSpec
object [(Text
"type", VLSpec
ptype), (Text
"coordinates", VLSpec
cs)]


{-|

Generate a data source that is a sphere for bounding global geographic data.
The sphere will be subject to whatever projection is specified for the view.

@
'Graphics.Vega.VegaLite.toVegaLite'
    [ 'sphere'
    , 'projection' [ 'PrType' 'Orthographic' ]
    , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' [ 'Graphics.Vega.VegaLite.MFill' "aliceblue" ]
    ]
@

@since 0.4.0.0
-}
sphere :: Data
sphere :: PropertySpec
sphere = (VLProperty
VLData, [LabelledSpec] -> VLSpec
object [Text
"sphere" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
True])


{-|

Generate a grid of lines of longitude (meridians) and latitude
(parallels).

@
let proj = 'projection' [ 'PrType' 'Orthographic' ]
    sphereSpec = 'Graphics.Vega.VegaLite.asSpec' [ 'sphere'
                        , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' [ 'Graphics.Vega.VegaLite.MFill' "aliceblue" ] ]
    gratSpec =
        'Graphics.Vega.VegaLite.asSpec'
            [ 'graticule' [ 'GrStep' (5, 5) ]
            , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' [ 'Graphics.Vega.VegaLite.MFilled' False, 'Graphics.Vega.VegaLite.MStrokeWidth' 0.3 ]
            ]
in 'Graphics.Vega.VegaLite.toVegaLite' [ proj, 'Graphics.Vega.VegaLite.layer' [ sphereSpec, gratSpec ] ]
@

@since 0.4.0.0

-}
graticule ::
  [GraticuleProperty] -- ^ An empty list uses the default parameters
  -> Data
graticule :: [GraticuleProperty] -> PropertySpec
graticule [] = (VLProperty
VLData, [LabelledSpec] -> VLSpec
object [Text
"graticule" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
True])
graticule [GraticuleProperty]
grProps =
  (VLProperty
VLData, [LabelledSpec] -> VLSpec
object [Text
"graticule" Text -> VLSpec -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [LabelledSpec] -> VLSpec
object ((GraticuleProperty -> LabelledSpec)
-> [GraticuleProperty] -> [LabelledSpec]
forall a b. (a -> b) -> [a] -> [b]
map GraticuleProperty -> LabelledSpec
graticuleProperty [GraticuleProperty]
grProps)])


{-|

Determine the properties of graticules. See the
<https://vega.github.io/vega-lite/docs/data.html#graticule Vega-Lite documentation> for details.

@since 0.4.0.0

-}
data GraticuleProperty
    = GrExtent (Double, Double) (Double, Double)
    -- ^ Define the extent of both the major and minor graticules.
    --   The range is given as longitude, latitude pairs of the
    --   minimum and then maximum extent. The units are degrees.
    | GrExtentMajor (Double, Double) (Double, Double)
    -- ^ As @GrExtent@ but for the major graticule lines only.
    | GrExtentMinor (Double, Double) (Double, Double)
    -- ^ As @GrExtent@ but for the minor graticule lines only.
    | GrStep (Double, Double)
    -- ^ The step angles for the graticule lines, given as a longitude,
    --   latitude pair defining the EW and NS intervals respectively.
    --   The units are degrees.
    --
    --   By default major graticule lines extend to both poles but the
    --   minor lines stop at ±80 degrees latitude.
    | GrStepMajor (Double, Double)
    -- ^ As @GrStep@ but for the major graticule lines only.
    --
    --   The default is @(90, 360)@.
    | GrStepMinor (Double, Double)
    -- ^ As @GrStep@ but for the minor graticule lines only.
    --
    --   The default is @(10, 10)@.
    | GrPrecision Double
    -- ^ The precision of the graticule. The units are degrees.
    --   A smaller value reduces visual artifacts (steps) but takes longer
    --   to render.
    --
    --   The default is @2.5@.


graticuleProperty :: GraticuleProperty -> LabelledSpec
graticuleProperty :: GraticuleProperty -> LabelledSpec
graticuleProperty (GrExtent (Double
lng1, Double
lat1) (Double
lng2, Double
lat2)) =
  Text
"extent" Text -> [[Double]] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Double
lng1, Double
lat1], [Double
lng2, Double
lat2]]
graticuleProperty (GrExtentMajor (Double
lng1, Double
lat1) (Double
lng2, Double
lat2)) =
  Text
"extentMajor" Text -> [[Double]] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Double
lng1, Double
lat1], [Double
lng2, Double
lat2]]
graticuleProperty (GrExtentMinor (Double
lng1, Double
lat1) (Double
lng2, Double
lat2)) =
  Text
"extentMinor" Text -> [[Double]] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Double
lng1, Double
lat1], [Double
lng2, Double
lat2]]
graticuleProperty (GrStep (Double
lng, Double
lat)) = Text
"step" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lng, Double
lat]
graticuleProperty (GrStepMajor (Double
lng, Double
lat)) = Text
"stepMajor" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lng, Double
lat]
graticuleProperty (GrStepMinor (Double
lng, Double
lat)) = Text
"stepMinor" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lng, Double
lat]
graticuleProperty (GrPrecision Double
x) = Text
"precision" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x