Giter Club home page Giter Club logo

Comments (9)

evancz avatar evancz commented on May 17, 2024

It is generated code, but I edit it directly to add imperative stuff as necessary.

I am happy to make the Line -> Form functions more robust. I am thinking of a super general one that lets you specify thickness, pattern, color, and how the line ends (rounded or squared). That could be used to define pretty much any kind of Line -> Form function (or points -> Form functions) you want.

I have reservations about your suggestions though. I do not like the idea that thickness can be applied to any Form. What does it mean to set the thickness of a sprite? Or an Element that has a border?

The second suggestion seems to hinge on functions like dotted :: Color -> Form -> Form which has the same problem as thickness. I`d rather avoid this kind of ambiguity.

Here's my long term plan for forms, shapes, and lines. I'd like to have functions like:

intersection :: Shape -> Shape -> Shape
union :: Shape -> Shape -> Shape
setTextOn :: Line -> Text -> Form

And once there are typeclasses, I'd like to make move, scale, rotate, isWithin, etc work on lines and shapes as well as on forms. Maybe this is less useful than I think, but I'd rather wait to see than give it up now.

To get the default behavior you are describing, maybe there could be functions like:

segmentSB :: Point -> Point -> Form
lineSB :: [Point] -> Form

Where SB is "solid black". Or maybe sbSegment and sbLine. In any case, I do not want to give up on the Line abstraction, at least not in the core library.

from compiler.

joeyadams avatar joeyadams commented on May 17, 2024

Thanks, you make very good points.

I'd still like to see a styling system that can be extended without breakage. Another idea might be:

data LineStyle -- abstract
lineColor :: Color -> LineStyle
solid, dashed, dotted :: LineStyle
customLineStyle :: [Number] -> Color -> LineStyle

line :: [LineStyle] -> Line -> Form

-- Renamed from 'line'
path :: [(Number,Number)] -> Line

Thus, line [] (segment (0, 0) (0, 0)) uses the default style (solid), color (black), and thickness (1.0).

from compiler.

evancz avatar evancz commented on May 17, 2024

I like this approach more. It is similar to how I ended up changing the HTTP library (old, new). Also, I really really like the name path; I've been trying to think of something more mathematically correct than line for a while.

There are still some ambiguities that can be avoided though. For example:

line [solid, dashed, dotted] (segment p1 p2)

I'll try an API now, keeping an eye on these docs so that it is as general as possible. This first part is about filling shapes and lines:

filled :: FillStyle fs =>  fs -> Shape -> Form
solid, dotted, dashed :: FillStyle fs => fs -> Line -> Form

instance FillStyle Color
instance FillStyle Gradient
instance FillStyle Texture

linearGradient :: Point -> Point -> [(Float,Color)] -> Gradient
radialGradient :: Point -> Float -> Point -> Float -> [(Float,Color)] -> Gradient
texture :: String -> Texture

This next part is about lines:

outlined :: StrokeStyle ss => ss -> Shape -> Form
line :: StrokeStyle ss => ss -> Line -> Form

instance StrokeStyle LineStyle
instance StrokeStyle Color
instance StrokeStyle LinePattern

customLineStyle :: FillStyle s => LineCap -> LineJoin -> Number -> LinePattern -> s -> LineStyle
lineStyle :: FillStyle s => Number -> LinePattern -> s -> LineStyle

buttCap, roundCap, squareCap :: LineCap

miterJoin, bevelJoin, roundJoin :: LineJoin
miterJoin' :: Number -> LineJoin

solidPattern, dashedPattern, dottedPattern :: LinePattern
customPattern :: [Number] -> LinePattern

I believe that none of this should cause any breaking changes.

As a side note, this seems like a fun function:

position :: Line -> Float -> (Number,Number)

Which would return the position that is some percentage along the given path. This might make it easier to move forms around in a nice way.

from compiler.

evancz avatar evancz commented on May 17, 2024

Maybe line could be named traced.

Also, this is much more complicated than I anticipated!

from compiler.

evancz avatar evancz commented on May 17, 2024

I am also really tempted to totally rename type Line to Path. I like it much more, but I am not sure if the Path vs FilePath ambiguity would be annoying.

from compiler.

evancz avatar evancz commented on May 17, 2024

Also, maybe rename LinePattern to LineStroke or Stroke.

from compiler.

joeyadams avatar joeyadams commented on May 17, 2024

There are still some ambiguities that can be avoided though. For example:

line [solid, dashed, dotted] (segment p1 p2)

My two cents: don't worry about it! You have the same situation in imperative code:

ctx.strokeStyle = 'black';
ctx.strokeStyle = 'blue';

in JavaScript object notation:

var obj = {a: 'black', a: 'blue'};

and even in Haskell's Data.Map:

Map.fromList [("a", "black"), ("a", "blue")]

In all of these cases, "blue" overrides "black" because it is listed last. So for:

line [solid, dashed, dotted] (segment p1 p2)

Just make dotted shadow the conflicting styles, as it is listed last.

from compiler.

evancz avatar evancz commented on May 17, 2024

Sorry for the delay, I have been without internet for a bit. I see the convenience of it, but I think the larger issue is "how do you do optional arguments in a functional language with type inference?" and as far as I know, there is not a nice way to do it.

I think maps and dictionaries are not comparable because that is a problem where types cannot rule out ambiguities and conflicts. An association list can have duplicate keys and (short of dependent types) that's just the way it is. So fromList accommodates this. We are not in that situation though. For us, it is possible to rule out ambiguities and conflicts at the type level and I think that is valuable.

That said, your proposal appears to be simple and nice. I am not sure if it would end up being simpler once it is fully fleshed out, but I suspect it might. My biggest hesitation is that I have never seen an API like this in a functional language in a comparable situation (i.e. when types could be used to resolve ambiguities). Do you know of any libraries or languages that expose APIs like the one you suggest? If not, why should Elm be the first language to do so?

from compiler.

evancz avatar evancz commented on May 17, 2024

This got added! It's definitely in 0.8 and 0.9 :)

from compiler.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.