-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add gradient support #9
Comments
I'd like to begin working on adding gradients to diagrams, I don't know if it will be ready by 1.0, but who knows. We have a number of design decisions to make before I start. Over the next view days I'll post some options to get a discussion started. If anyone knows of anyone previous discussion please let me know. |
I don't have much to add yet, but the pdf backend does have graident On Thu, Oct 17, 2013 at 9:28 PM, Jeffrey Rosenbluth <
|
As I see it the first bridge to cross is deciding between the following 2 options.
|
I take it the Gradient type includes a color, possibly two colors? I think user code that doesn't use gradients should still be able to write (2) will clearly break all the Backends. (1) also has clear behavior for Backends which do not support gradients. If you go with (2), I'd like documentation of how such Backends should fall back to solid color. For these reasons, I have a slight preference for (1). |
Yes the Gradient type should include a list of stops and colors plus several other fields. If we go with 1. we need to come up with a way to handle the case where an instance of type class HasStyle could contain both FillColor and FillGradient attributes. I don't think leaving it up to the backends to sort this out is a good idea. One way to handle this is to insure that this never happens. This could be accomplished by augmenting the data structure of attributes to carry a list of "similar attributes" so that we can check for example if a style has a FillColor attribute before adding a FillGradient attribute if FillColor is in FillGradient's similar attributes list. This is quite an invasive change however as all attribute semigroup definitions would need to change as will as the Style semigroup. The advantage of 2. is this case could not occur. On the other hand gradients should be Transformable, but FillColor is not, this is a further complication to option 2, although I don't think making FillColor transformable where transformations have no effect is so bad. In the end I think 2. is the cleaner solution, but as bergey points out it will break the backends. |
The gradient data structure should look something like this type GradientStop = (SomeColor, Double)
data SpreadMethod = GradPad | GradReflect | GradRepeat
data LinearGradient p = LinearGradient { _lGradStops :: [GradientStop]
, _lGradStart :: p
, _lGradSEnd :: p
, _lGradSpreadMethod :: SpreadMethod }
data RadialGradient p = RadialGradient { _rGradStops :: [GradientStop]
, _rGradRadius :: Double
, _rGradCenter :: p
, _rGradFocus :: p
, _rGradSpreadMethod :: SpreadMethod }
basically following SVG. |
I think option 2 would go something like this where I have begun to implement linear and radial gradients for stroking. data SomeColor = forall c. Color c => SomeColor c
type GradientStop = (SomeColor, Double)
data SpreadMethod = GradPad | GradReflect | GradRepeat
-- | Linear Gradient
data LGradient = forall p. AffineSpace p => LGradient
{ _lGradStops :: [GradientStop]
, _lGradStart :: p
, _lGradSEnd :: p
, _lGradSpreadMethod :: SpreadMethod }
makeLenses ''LGradient
-- | Radial Gradient
data RGradient = forall p. AffineSpace p => RGradient
{ _rGradStops :: [GradientStop]
, _rGradRadius :: Double
, _rGradCenter :: p
, _rGradFocus :: p
, _rGradSpreadMethod :: SpreadMethod }
makeLenses ''RGradient
data Texture = SC SomeColor | LG LGradient | RG RGradient
deriving Typeable
newtype LineTexture = LineTexture (Last Texture)
deriving (Typeable, Semigroup)
instance AttributeClass LineTexture
instance Default LineTexture where
def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))
getLineTexture :: LineTexture -> Texture
getLineTexture (LineTexture (Last t)) = t
lineTexture :: HasStyle a => Texture -> a -> a
lineTexture = applyAttr . LineTexture . Last
lineColor :: (Color c, HasStyle a) => c -> a -> a
lineColor c = lineTexture (SC (SomeColor c)) |
I think your earlier version, polymorphic over the point type (or better, the vector space), was correct. Can you actually write a I think it's simple enough to specify Backend behavior when there's both a One downside is that to override a gradient we'll need to write |
The code above actually compiles when I drop it into Attributes.hs so I suspect you can write a I guess letting the backends handle I'd like to hear what others think as well. |
I agree with @bergey, |
hmm. The intent was for |
OK, maybe I just don't understand the semantics of |
OK, I have read up on gradients and I understand a bit better now. I am still not convinced about the existential quantification. What is its purpose? Even if you do I would expect something like data LGradient v = LGradient
{ _lGradStops :: [GradientStop]
, _lGradStart :: Point v
... That is, the type of a gradient has to tell you what vector space it lives in. Otherwise how would you know what its relationship is with other things that live in some vector space? (Also, I have intentionally not given any thought to the questions about how to structure things with gradients and fill colors, breaking backends, etc.; I have enough things to think about at the moment, it doesn't seem pressing, and I trust the rest of you to think it through and come up with something reasonable.) |
Ah, I see where I went wrong. Oh, I didn't see the parenthetical to you comment, go ahead and disregard my last question? |
@bergey Hard to say where the backends should take their color from is they don't support gradients. Depending on where the user assumes the light is coming from any of the stops could make the most sense. Perhaps the backend should just ignore gradients and us the default color - i.e. clear. |
Adding gradients for strokes might look something like this for
thoughts? class Color c where
-- | Convert a color to its standard representation, AlphaColour
toAlphaColour :: c -> AlphaColour Double
-- | An existential wrapper for instances of the 'Color' class.
data SomeColor = forall c. Color c => SomeColor c
type GradientStop = (SomeColor, Double)
data SpreadMethod = GradPad | GradReflect | GradRepeat
-- | Linear Gradient
data LGradient = LGradient
{ _lGradStops :: [GradientStop]
, _lGradStart :: P2
, _lGradSEnd :: P2
, _lGradSpreadMethod :: SpreadMethod }
makeLenses ''LGradient
-- | Radial Gradient
data RGradient = RGradient
{ _rGradStops :: [GradientStop]
, _rGradRadius :: Double
, _rGradCenter :: P2
, _rGradFocus :: P2
, _rGradSpreadMethod :: SpreadMethod }
makeLenses ''RGradient
data Texture = SC SomeColor | LG LGradient | RG RGradient
deriving (Typeable)
newtype LineTexture = LineTexture (Last Texture)
deriving (Typeable, Semigroup)
instance AttributeClass LineTexture
type instance V LineTexture = R2
instance Transformable LineTexture where
transform t l@(LineTexture (Last (SC _))) = l
-- XXX Need to handle linear and radial grandient transforms.
transform t l@(LineTexture lt) = l
instance Default LineTexture where
def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))
getLineTexture :: LineTexture -> Texture
getLineTexture (LineTexture (Last t)) = t
lineTexture :: (HasStyle a, V a ~ R2) => Texture-> a -> a
lineTexture = applyTAttr . LineTexture . Last
lineColor :: (Color c, HasStyle a, V a ~ R2) => c -> a -> a
lineColor c = lineTexture (SC (SomeColor c))
-- | A synonym for 'lineColor', specialized to @'Colour' Double@
-- (i.e. opaque colors).
lc :: (HasStyle a, V a ~ R2) => Colour Double -> a -> a
lc = lineColor
-- | A synonym for 'lineColor', specialized to @'AlphaColour' Double@
-- (i.e. colors with transparency).
lcA :: (HasStyle a, V a ~ R2) => AlphaColour Double -> a -> a
lcA = lineColor
lineLGradient :: (HasStyle a, V a ~ R2) => LGradient -> a -> a
lineLGradient g = lineTexture (LG g)
lineRGradient :: (HasStyle a, V a ~ R2) => RGradient -> a -> a
lineRGradient g = lineTexture (RG g) |
I think you're right that the sort of textures and patterns we'd want to support in 3D are quite different from these. But the plan for 3D is to not use |
Problem transforming gradients - see, https://github.com/jeffreyrosenbluth/diagrams-gallery/blob/master/gradient.svg |
(Imported from http://code.google.com/p/diagrams/issues/detail?id=21. Original issue from byor...@gmail.com on April 9, 2011, 12:10:27 AM UTC)
Many backends support gradients of various types. A module for describing gradients should be added to the standard library along with functions for setting the gradient attribute of a diagram.
The text was updated successfully, but these errors were encountered: